Moved logic for computing matrix out of h1_element

This commit is contained in:
Montessinos Mickael Gerard Bernard 2024-03-07 12:24:54 +02:00
parent 6fd6176ff8
commit 9a51dfff7c
3 changed files with 455 additions and 100 deletions

View File

@ -57,7 +57,7 @@ def canonical_bundle(K):
sage: L == trivial_bundle(K)
True
"""
pi,_ = function_field_utility.safe_uniformizer(K)
pi = function_field_utility.safe_uniformizers(K)[0]
return VectorBundle(K, pi.differential().divisor())
def _euclid(a,b):

View File

@ -2,6 +2,9 @@ r"""
Implementations of all sort of algorithms for function field that are not
yet implemented in Sage.
A lot of code for the FunctionFieldCompletionCustom class comes directly
from the sage source, and was written by Kwankyu Lee.
REFERENCE:
.. [Coh00] H. Cohen
Advanced topics in computational number theory
@ -18,7 +21,9 @@ r"""
###########################################################################
from sage.matrix.constructor import matrix
from sage.rings.infinity import Infinity
from sage.categories.map import Map
from sage.modules.free_module_element import vector
from sage.rings.infinity import infinity
from copy import copy
from sage.misc.cachefunc import cached_function
from sage.misc.misc_c import prod
@ -30,6 +35,7 @@ from sage.rings.function_field.function_field_rational\
from sage.rings.function_field.order_rational\
import FunctionFieldMaximalOrderInfinite_rational
from sage.rings.function_field.order import FunctionFieldOrderInfinite
from sage.rings.function_field.ideal import FunctionFieldIdealInfinite
@cached_function
def all_infinite_places(K):
@ -60,7 +66,7 @@ def infinite_valuation(a):
1
"""
if a == 0:
return Infinity
return infinity
return a.denominator().degree() - a.numerator().degree()
@ -82,7 +88,7 @@ def infinite_mod(a,i):
def infinite_integral_matrix(mat):
r"""
Return an matrix with coefficient in the infinite maximal order and its denominator.
Return a matrix with coefficient in the infinite maximal order and its denominator.
INPUT:
@ -289,55 +295,296 @@ def infinite_approximation(places,valuations,residues):
@cached_function
def safe_uniformizer(K):
def safe_uniformizers(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: from vector_bundle.function_field_utility import safe_uniformizers
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]
sage: pis = safe_uniformizers(K)
sage: all([(pi.valuation(place) == 1 and i == j) or (pi.valuation(place) == 0 and i != j) for (i,pi) in enumerate(pis) for (j, place) in enumerate(places)])
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(
return [infinite_approximation(
places,
[2] + ([1]*(n-1)),
[places[0].local_uniformizer()] + ([1]*(n-1))),
places[0])
[2 if p == place else 1 for p in places],
[place.local_uniformizer() if p == place else 1 for p in places])
for place in places]
class FunctionFieldCompletionCustom(Map):
"""
Completions on function fields.
Allows for choice of uniformizer.
INPUT:
- ``field`` -- function field
- ``place`` -- place of the function field
- ``pi`` -- a local uniformizer at place
- ``name`` -- string for the name of the series variable
- ``prec`` -- positive integer; default precision
- ``gen_name`` -- string; name of the generator of the residue
field; used only when place is non-rational
EXAMPLES::
sage: from vector_bundle.function_field_utility import FunctionFieldCompletionCustom
sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[]
sage: L.<y> = K.extension(Y^2 + Y + x + 1/x)
sage: p = L.places_finite()[0]
sage: m = FunctionFieldCompletionCustom(L,p)
sage: m
Completion map:
From: Function field in y defined by y^2 + y + (x^2 + 1)/x
To: Laurent Series Ring in s over Finite Field of size 2
sage: m(x)
s^2 + s^3 + s^4 + s^5 + s^7 + s^8 + s^9 + s^10 + s^12 + s^13
+ s^15 + s^16 + s^17 + s^19 + O(s^22)
sage: m(y)
s^-1 + 1 + s^3 + s^5 + s^7 + s^9 + s^13 + s^15 + s^17 + O(s^19)
sage: m(x*y) == m(x) * m(y)
True
sage: m(x+y) == m(x) + m(y)
True
The variable name of the series can be supplied. If the place is not
rational such that the residue field is a proper extension of the constant
field, you can also specify the generator name of the extension::
sage: p2 = L.places_finite(2)[0]
sage: p2
Place (x^2 + x + 1, x*y + 1)
sage: m2 = FunctionFieldCompletionCustom(L, p2, name='t', gen_name='b')
sage: m2(x)
(b + 1) + t + t^2 + t^4 + t^8 + t^16 + O(t^20)
sage: m2(y)
b + b*t + b*t^3 + b*t^4 + (b + 1)*t^5 + (b + 1)*t^7 + b*t^9 + b*t^11
+ b*t^12 + b*t^13 + b*t^15 + b*t^16 + (b + 1)*t^17 + (b + 1)*t^19 + O(t^20)
The choice of local uniformizer used for the expansion can be supplied.
sage: from vector_bundle.function_field_utility import safe_uniformizers
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**-5 - 1)
sage: pi = safe_uniformizers(K)[0]
sage: place = all_infinite_places(K)[0]
sage: f = 1 / (1-pi)
sage: m3 = FunctionFieldCompletionCustom(K, place, pi)
sage: m3(f)
1 + s + s^2 + s^3 + s^4 + s^5 + s^6 + s^7 + s^8 + s^9 + s^10 + s^11 +
s^12 + s^13 + s^14 + s^15 + s^16 + s^17 + s^18 + s^19 + O(s^20)
"""
def __init__(self, field, place, pi=None, name=None, prec=None, gen_name=None):
"""
Initialize.
EXAMPLES::
sage: # needs sage.rings.finite_rings sage.rings.function_field
sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[]
sage: L.<y> = K.extension(Y^2 + Y + x + 1/x)
sage: p = L.places_finite()[0]
sage: m = L.completion(p)
sage: m
Completion map:
From: Function field in y defined by y^2 + y + (x^2 + 1)/x
To: Laurent Series Ring in s over Finite Field of size 2
"""
if name is None:
name = 's' # default
if gen_name is None:
gen_name = 'a' # default
k, from_k, to_k = place.residue_field(name=gen_name)
self._place = place
if pi is None:
self._pi = place.local_uniformizer()
else:
self._pi = pi
self._gen_name = gen_name
if prec is infinity:
from sage.rings.lazy_series_ring import LazyLaurentSeriesRing
codomain = LazyLaurentSeriesRing(k, name)
self._precision = infinity
else: # prec < infinity:
# if prec is None, the Laurent series ring provides default precision
from sage.rings.laurent_series_ring import LaurentSeriesRing
codomain = LaurentSeriesRing(k, name=name, default_prec=prec)
self._precision = codomain.default_prec()
Map.__init__(self, field, codomain)
def _repr_type(self) -> str:
"""
Return a string containing the type of the map.
EXAMPLES::
sage: # needs sage.rings.finite_rings sage.rings.function_field
sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[]
sage: L.<y> = K.extension(Y^2 + Y + x + 1/x)
sage: p = L.places_finite()[0]
sage: m = L.completion(p)
sage: m # indirect doctest
Completion map:
From: Function field in y defined by y^2 + y + (x^2 + 1)/x
To: Laurent Series Ring in s over Finite Field of size 2
"""
return 'Completion'
def _call_(self, f):
"""
Call the completion for f
EXAMPLES::
sage: # needs sage.rings.finite_rings sage.rings.function_field
sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[]
sage: L.<y> = K.extension(Y^2 + Y + x + 1/x)
sage: p = L.places_finite()[0]
sage: m = L.completion(p)
sage: m(y)
s^-1 + 1 + s^3 + s^5 + s^7 + s^9 + s^13 + s^15 + s^17 + O(s^19)
"""
if f.is_zero():
return self.codomain().zero()
if self._precision is infinity:
return self._expand_lazy(f)
else:
return self._expand(f, prec=None)
def _call_with_args(self, f, args, kwds):
"""
Call the completion with ``args`` and ``kwds``.
EXAMPLES::
sage: # needs sage.rings.finite_rings sage.rings.function_field
sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[]
sage: L.<y> = K.extension(Y^2 + Y + x + 1/x)
sage: p = L.places_finite()[0]
sage: m = L.completion(p)
sage: m(x+y, 10) # indirect doctest
s^-1 + 1 + s^2 + s^4 + s^8 + O(s^9)
"""
if f.is_zero():
return self.codomain().zero()
if self._precision is infinity:
return self._expand_lazy(f, *args, **kwds)
else:
return self._expand(f, *args, **kwds)
def _expand(self, f, prec=None):
"""
Return the Laurent series expansion of f with precision ``prec``.
INPUT:
- ``f`` -- element of the function field
- ``prec`` -- positive integer; relative precision of the series
EXAMPLES::
sage: # needs sage.rings.finite_rings sage.rings.function_field
sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[]
sage: L.<y> = K.extension(Y^2 + Y + x + 1/x)
sage: p = L.places_finite()[0]
sage: m = L.completion(p)
sage: m(x, prec=20) # indirect doctest
s^2 + s^3 + s^4 + s^5 + s^7 + s^8 + s^9 + s^10 + s^12 + s^13 + s^15
+ s^16 + s^17 + s^19 + O(s^22)
"""
if prec is None:
prec = self._precision
place = self._place
F = place.function_field()
der = F.higher_derivation()
k, from_k, to_k = place.residue_field(name=self._gen_name)
sep = self._pi
val = f.valuation(place)
e = f * sep**(-val)
coeffs = [to_k(der._derive(e, i, sep)) for i in range(prec)]
return self.codomain()(coeffs, val).add_bigoh(prec + val)
def _expand_lazy(self, f):
"""
Return the lazy Laurent series expansion of ``f``.
INPUT:
- ``f`` -- element of the function field
EXAMPLES::
sage: # needs sage.rings.finite_rings sage.rings.function_field
sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[]
sage: L.<y> = K.extension(Y^2 + Y + x + 1/x)
sage: p = L.places_finite()[0]
sage: m = L.completion(p, prec=infinity)
sage: e = m(x); e
s^2 + s^3 + s^4 + s^5 + s^7 + s^8 + ...
sage: e.coefficient(99) # indirect doctest
0
sage: e.coefficient(100)
1
"""
place = self._place
F = place.function_field()
der = F.higher_derivation()
k, from_k, to_k = place.residue_field(name=self._gen_name)
sep = self._pi
val = f.valuation(place)
e = f * sep**(-val)
def coeff(s, n):
return to_k(der._derive(e, n - val, sep))
return self.codomain().series(coeff, valuation=val)
def default_precision(self):
"""
Return the default precision.
EXAMPLES::
sage: # needs sage.rings.finite_rings sage.rings.function_field
sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[]
sage: L.<y> = K.extension(Y^2 + Y + x + 1/x)
sage: p = L.places_finite()[0]
sage: m = L.completion(p)
sage: m.default_precision()
20
"""
return self._precision
def local_expansion(place,pi,f):
r"""
@ -359,26 +606,7 @@ def local_expansion(place,pi,f):
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
@ -574,22 +802,50 @@ def euclidean_step(ideal_a, ideal_b, a, b, d=None):
return s/a, t/b
def finite_integral_quotient(left, right):
return (left.numerator()*right.denominator()) // (left.denominator())*(right.numerator())
def infinite_integral_quotient(left, right):
if left == 0:
return 0
r = left / right
x = left.parent().gen()
return x**(r.denominator().degree() - r.numerator().degree())
def hnf_reduction_mod_ideal(ideal, elem):
r"""
Reduce an element of a function field \(K\) modulo an ideal of a maximal
order of K
"""
if isinstance(ideal, FunctionFieldIdealInfinite):
quotient = infinite_integral_quotient
hnf = infinite_ideal_hnf(ideal)
else:
quotient = finite_integral_quotient
hnf = ideal.hnf()
n = hnf.ncols()
basis = ideal.base_ring().basis()
basis_matrix = matrix([e.list() for e in basis]).transpose()**-1
y = basis_matrix * matrix(n,1,elem.list())
for i in range(n - 1, -1, -1):
q = quotient(y[i,0],hnf[i,i])
y -= q * hnf[:,i]
y = sum([y[i,0]*e for i, e in enumerate(basis)])
return y
def pseudo_hermite_form(ideals, mat, include_zero_cols=True, transformation=False):
r"""
Return the hermite form of the pseudo-matrix ``(ideals, mat)`` with
coefficients in a function field and ideals in a maximal order.
If the maximal order is infinite, the ideals of the pseudo-matrix output
are all trivial.
WARNING:
Uses the opposite convention from sage for hermite forms, aligns with
Cohen's book instead.
The final reduction step is not implemented as having triangular matrices
is enough for our purposes.
ALGORITHM:
- Algorithm 1.4.7 from [Coh00]_
@ -604,8 +860,8 @@ def pseudo_hermite_form(ideals, mat, include_zero_cols=True, transformation=Fals
sage: mat = matrix(K, [[1, x, y],[2, x+1, y+1]])
sage: h_ideals, h, u = pseudo_hermite_form(ideals, mat, transformation=True)
sage: h
[ 0 1 (2*x + 5)*y + 4*x]
[ 0 0 1]
[ 0 1 3*x^3 + 4*x]
[ 0 0 1]
sage: h == mat * u
True
sage: all([u[i,j] in ideals[i] * h_ideals[j]^-1 for i in range(3) for j in range(3)])
@ -622,6 +878,9 @@ def pseudo_hermite_form(ideals, mat, include_zero_cols=True, transformation=Fals
j = k-1
for i in range(n-1, -1, -1):
#Check zero
if not h[i,:]:
j -= 1
continue
m = [h[i,m] == 0 for m in range(j, -1, -1)].index(False)
h[:,m], h[:,j] = h[:,j], h[:,m]
U[:,m], U[:,j] = U[:,j], U[:,m]
@ -641,9 +900,12 @@ def pseudo_hermite_form(ideals, mat, include_zero_cols=True, transformation=Fals
U[:, m], U[:, j] = U[:, m] - h[i, m]*U[:, j], u*U[:, m] + v*U[:, j]
h[:, m], h[:, j] = h[:, m] - h[i, m]*h[:, j], u*h[:, m] + v*h[:, j]
h_ideals[m], h_ideals[j] = h_ideals[m] * h_ideals[j] * partial**-1, partial
#Final reduction of row i
#Not implemented for the moment since we only need triangular matrices
#for our current purposes.
#Row reduction step
for m in range(j+1,k):
ideal = h_ideals[m]**-1 * h_ideals[j]
q = h[i, m] - hnf_reduction_mod_ideal(ideal, h[i, m])
U[:, m] -= q*U[:, j]
h[:, m] -= q*h[:, j]
j -=1
if not include_zero_cols:
h = h[:,k-n:]
@ -652,3 +914,103 @@ def pseudo_hermite_form(ideals, mat, include_zero_cols=True, transformation=Fals
if transformation:
return h_ideals, h, U
return h_ideals, h
def hermite_form_infinite_polymod(mat, include_zero_cols=True, transformation=False):
r"""
Return the hermite normal form of mat.
EXAMPLES ::
sage: from vector_bundle.function_field_utility import hermite_form_infinite_polymod
sage: from vector_bundle.function_field_utility import all_infinite_places
sage: F.<x> = FunctionField(GF(7))
sage: R.<y> = F[]
sage: K.<y> = F.extension(y^2 - x^3 - x)
sage: mat = matrix(K,[[1,x^-1,y^-1],[2,(x+1)^-1,(y+1)^-1]])
sage: h, u = hermite_form_infinite_polymod(mat, transformation=True)
sage: h
[ 0 (4*x + 1)/(x^2 + x) (4*x^2 + 6)/x^2]
[ 0 0 1]
sage: h == mat * u
True
sage: O = K.maximal_order_infinite()
sage: all([c in O for c in u.list()])
True
sage: all([u.determinant().valuation(place) == 0 for place in all_infinite_places(K)])
True
"""
K = mat.base_ring()
O = K.maximal_order_infinite()
pis = safe_uniformizers(K)
places = all_infinite_places(K)
mins = [min([m.valuation(place) for m in mat.list()]) for place in places]
den = prod([pi**min(-m,0) for pi, m in zip(pis, mins)])
h = den*mat
k = mat.ncols()
n = mat.nrows()
U = identity_matrix(K,k)
j = k-1
for i in range(n-1, -1, -1):
if not h[i,:]:
continue
min_vals = [min([h[i,m].valuation(place) for m in range(j+1)])
for place in places]
gcd = prod([pi**m for pi, m in zip(pis, min_vals)])
#put gcd on the diagonal
ideals = [O.ideal(h[i,m]/gcd) for m in range(j+1)]
coefs = infinite_order_xgcd(ideals)
m = [c == 0 for c in coefs].index(False)
U[:,j], U[:, m] = gcd*sum([c/h[i,m]*U[:,m]
for m,c in enumerate(coefs)]), U[:, j]
h[:,j], h[:, m] = gcd*sum([c/h[i,m]*h[:,m]
for m,c in enumerate(coefs)]), h[:, j]
assert(all([u in O for u in U.list()]))
#eliminate coefficients left of diagonal
for m in range(j):
c = h[i,m]/h[i,j]
U[:,m] -= c*U[:,j]
h[:,m] -= c*h[:,j]
assert(all([u in O for u in U.list()]))
#reduce coefficients right of diagonal
for m in range(j+1,k):
ideal = O.ideal(h[i,j])
q = (h[i, m] - hnf_reduction_mod_ideal(ideal,h[i, m]))/h[i,j]
U[:,m] -= q*U[:,j]
h[:,m] -= q*h[:,j]
j-=1
h /= den
if not include_zero_cols:
h = h[:,k-n:]
U = U[:,k-n:]
if transformation:
return h, U
return h
def full_rank_matrix_in_completion(mat, place=None, pi=None):
r"""
Return a full rank matrix with coefficients in the constant base field.
Its columns are concatenations of expansions of the coefficients in the
columns of mat.
"""
K = mat.base_ring()
k = K.constant_base_field()
s = mat.ncols()
r = mat.nrows()
if place is None:
if isinstance(K, RationalFunctionField):
place = K.gen().zeros()[0]
else:
place = K.get_place(1)
Kp = FunctionFieldCompletionCustom(K, place, pi, prec=infinity, name="pi", gen_name="b")
exps = [[Kp(c) for c in row] for row in mat]
vals = [min([mat[i,j].valuation(place) for j in range(s)])
for i in range(r)]
ell = 0
N = matrix(k,0,s)
while N.rank() < s:
for i in range(r):
row = [exps[i][j].coefficient(vals[i] + ell) for j in range(s)]
N = insert_row(N, (i+1)*(ell+1) - 1, row)
ell += 1
return N

View File

@ -922,7 +922,7 @@ class VectorBundle(SageObject):
OUTPUT:
- ''res'' -- vector of elements of K such that the corresponding infinite répartition vectorcorresponds to form under Serre duality with respect to _safe_uniformizer(self._function_field).differential().
- ''res'' -- vector of elements of K such that the corresponding infinite répartition vectorcorresponds to form under Serre duality with respect to ``safe_uniformizers(self._function_field)[0].differential()``.
EXAMPLES ::
@ -941,44 +941,38 @@ class VectorBundle(SageObject):
form = [1] + [0] * (s-1)
r = self.rank()
places = function_field_utility.all_infinite_places(K)
pi_0, place_0 = function_field_utility.safe_uniformizer(K)
if not place_0 == places[0]:
raise ValueError('Something went wrong with the order of infinite'
+ ' places of the function field')
pi_0 = function_field_utility.safe_uniformizers(K)[0]
place_0 = places[0]
k,from_k,to_k = place_0.residue_field()
form = vector([function_field_utility.invert_trace(
k, K.constant_base_field(), c) for c in form])
dual_matrix = matrix([h1_dual_bundle._matrix_to_vector(mat)
for mat in h1_dual]).transpose()
zero_rows = [i for i, row in enumerate(dual_matrix) if row == 0]
exps = [[function_field_utility.local_expansion(place_0,
pi_0,dual_matrix[i, j])
for j in range(s)]
for i in range(r)]
min_vals = [[min([dual_matrix[i, j].valuation(place) for j in range(s)])
for i in range(r)]
for place in places]
ell = 0
n_matrix = matrix(k,0,s,[])
while n_matrix.rank() < s:
for i in range(r):
row = [exps[i][j](min_vals[0][i] + ell) for j in range(s)]
n_matrix = function_field_utility.insert_row(
n_matrix, (i+1)*(ell+1) - 1, row)
ell +=1
n_matrix = function_field_utility.full_rank_matrix_in_completion(
dual_matrix,
place_0,
pi_0)
ell = n_matrix.nrows() // dual_matrix.nrows()
ell_pow = k.cardinality() ** integer_ceil(logb(ell,k.cardinality()))
res = n_matrix.solve_left(form)
min_vals = [[min([c.valuation(place) for c in dual_matrix.list()])]
for place in places]
pi = function_field_utility.infinite_approximation(
places,
[1] + [integer_ceil(-min(min_val)/ell) for min_val in min_vals[1:]],
[1] + [integer_ceil(-min_val/ell) for min_val in min_vals[1:]],
[1] + [0]*(len(places)-1))**ell_pow
res = [function_field_utility.infinite_approximation(
places,
[1] + [0]*(len(places)-1),
[a] + [0]*(len(places)-1))**ell_pow
for a in res]
min_vals_0 = [0 if i in zero_rows
else min([dual_matrix[i,j].valuation(place_0)
for j in range(s)])
for i in range(r)]
return [pi
* pi_0**(-min_vals[0][i]-1)
* pi_0**(-min_vals_0[i]-1)
* sum([pi_0**(-j) * res[i*ell + j] for j in range(ell)])
if not i in zero_rows else 0
for i in range(r)]
@ -1049,14 +1043,18 @@ class VectorBundle(SageObject):
for mat in ext_dual]
return ext_group.extension(form)
def is_isomorphic_to(self, other):
def _isomorphism_to_large_field(self, other, proba=10^-20):
r"""
Checks whether self is isomorphic to other
Return an isomorphism from self to other if it exists and None otherwise.
ALGORITHM:
May fail to find an isomorphism with probability less than proba.This
only works if the constant base field is larger than
``len(self.end().h0())``.
"""
Computes the space of global homomorphisms and looks for
an invertible matrix. Can probably be improved.
def isomorphism_to(self, other):
r"""
Return an isomorphism from self to other if it exists and None otherwise
EXAMPLES ::
@ -1066,10 +1064,5 @@ class VectorBundle(SageObject):
sage: K.<y> = F.extension(y^4 - x^-2 - 1)
sage: triv = trivial_bundle(K)
sage: can = canonical_bundle(K)
sage: triv.is_isomorphic_to(can)
True
sage: triv.isomorphism_to(can)
"""
mat_basis = self.hom(other).h0()
k = self._function_field.constant_base_field()
return any([sum([(c*mat).is_unit() for c, mat in zip(vec, mat_basis)])
for vec in ProjectiveSpace(len(mat_basis)-1, k)])