Path: blob/main/scripts/genus2_curves/g2LocSolv.py
1127 views
# -*- coding: utf-8 -*-12from sage.all import ZZ, sqrt, Set, valuation, kronecker_symbol, GF, floor, Mod, PolynomialRing, next_prime34def IsSquareInQp(x, p):5if x==0:6return True7# Check parity of valuation8v=valuation(x,p)9if v%2:10return False11# Renormalise to get a unit12x//=p**v13# Reduce mod p and conclude14if p==2:15return Mod(x,8)==116else:17return kronecker_symbol(x,p)==1181920def HasFinitePointAt(F, p, c):21"""22Tests whether y²=c*F(x) has a finite Qp-point with x and y both in Zp,23assuming that deg F = 6 and F integral24"""25Fp = GF(p)26if p > 2 and Fp(F.leading_coefficient()): # Tests to accelerate case of large p27# Write F(x) = c*lc(F)*R(x)²*S(x) mod p, R as big as possible28R = F.parent()(1)29S = F.parent()(1)30for X in (F.base_extend(Fp)/Fp(F.leading_coefficient())).squarefree_decomposition():31[G,v] = X # Term of the form G(x)^v in the factorisation of F(x) mod p32S *= G**(v%2)33R *= G**(v//2)34r = R.degree()35s = S.degree()36if s == 0: # F(x) = C*R(x)² mod p, C = c*lc(F) constant37if IsSquareInQp(c*F.leading_coefficient(),p):38if p>r:# Then there is x s.t. R(x) nonzero and C is a square39return True40#else: # C nonsquare, so if we have a Zp-point it must have R(x) = 0 mod p41#Z = R.roots()42##TODO43else:44g = S.degree()//2 - 1 # genus of the curve y²=C*S(x)45B = floor(p-1-2*g*sqrt(p)) # lower bound on number of points on y²=C*S(x) not at infty46if B > r+s: # Then there is a point on y²=C*S(x) not at infty and with R(x) and S(x) nonzero47return True48#Now p is small, we can run a naive search49q = p50Z = []51if p == 2:52q = 853for x in range(q):54y = F(x)55# If we have found a root, save it (take care of the case p=2!)56if (p > 2 or x < 2) and Fp(y) == 0:57Z.append(x)58# If we have a mod p point with y nonzero mod p, then it lifts, so we're done59if IsSquareInQp(c*y, p):60return True61#So now, if we have a Qp-point, then its y-coordinate must be 0 mod p62t = F.variables()[0]63for z in Z:64F1 = F(z+p*t)65c1 = F1.content()66F1 //= c167if HasFinitePointAt(F1,p,(c*c1).squarefree_part()):68return True69return False7071def IsSolubleAt(F, p):72"""73Tests whether y² = F(x) has a Qp-point, assuming F integral of degree 6 and lc(F) squarefree74"""75lc = F.leading_coefficient()76if lc % p:77# The leading coeff. a6 is not 0 mod p78# Are the points at Infty defined over Qp ?79if IsSquareInQp(lc,p):80return True81# If we have a point (x,y) with v_p(x) = -A, then v_p(f(x)) = v_p(a6*x^6) = -6A so v_p(y) = -3A82# So we have x = x'/p^A, y = y'/p^3A, with x' and y' p-adic units83# Renormalise : y'² = a_d x'^6 + a5 p^A x'^5 + a4 p^2A x'^4 + ...84if p > 2:85# Then a6 must be a square mod p, hence a square in Qp, contradiction86# So x and y must be in Zp87return HasFinitePointAt(F, p, 1)88else:89# x'6 = y'² = 1 mod 8, so if A >= 3, then a6 = 1 mod 8, contradiction. So A <= 2, renormalise.90t = F.variables()[0]91Zx = PolynomialRing(ZZ,'x')92return HasFinitePointAt(Zx(4**6*F(t/4)),2,1)93else:94# p || a695# In particular the points at Infty are not defined over Qp96# Let us try points over Zp first97if HasFinitePointAt(F,p,1):98return True99# Now, if we had a point with v_p(x) = -A, then v_p(a6 x^6) = 1-6A whereas the other terms have v_p >= -5A100# So if A >= 2, then 1-6A dominates, so v_p(f(x))=1-6A is odd, contradiction.101# So A=1, and there must be cancellation mod p to prevent v_p(f(x)) = 5102# --> x = -a5/a6 + O(p^0), and v_p(y) >= -2103# Just renormalise104a5 = F[F.degree()-1]105if a5 % p == 0:106return False107t = F.variables()[0]108Zx = PolynomialRing(ZZ,'x')109x0 = -a5/lc # v_p(x0) = -1, mustr have x = x0 + O(p^0)110x0 = ((p*x0)%p)/p # Clear non-p-part of denominator111return HasFinitePointAt(Zx(p**4*F(x0+t)),p,1)112113114def InsolublePlaces(f, h=0):115"""116List of primes at which the curve y²+h(x)*y=f(x) is not soluble117118Assumes f and h have integer coefficients119"""120S = [] # List of primes at which not soluble121# Get eqn of the form y²=F(x)122F = f123if h:124F = 4*f + h**2125# Do we have a rational point an Infty ?126if F.degree()%2 or F.leading_coefficient().is_square():127return []128# Treat case of RR129if F.leading_coefficient() < 0 and F.number_of_real_roots() == 0:130S.append(0)131# Remove squares from lc(F)132d = F.degree()133lc = F.leading_coefficient()134t = F.variables()[0]135a = lc.squarefree_part() # lc/a is a square136a = lc//a137Zx = PolynomialRing(ZZ,'x')138F = Zx(a**(d-1) * F(t/a))139# Find primes of bad reduction for our model140D = F.disc()141P = Set(D.prime_divisors())142# Add primes at which Weil bounds do not guarantee a mod p point143g = (d-2)//2144Weil = []145p = 2146while (p+1)**2 <= 4 * g**2 * p:147Weil.append(p)148p = next_prime(p)149P = P.union(Set(Weil))150# Test for solubility151for p in P:152if not IsSolubleAt(F,p):153S.append(p)154S.sort()155return S156157158## The next function is meant to be used with the "rewrite_collection" script". It adds the 'insoluble_places' entry to its argument.159160def Process_One(c):161Zx = PolynomialRing(ZZ,'x')162#label = str(c['label'])163#print "Updating",label164eqn = c['eqn']165f,h = eqn.split("],[")166f = Zx([int(x) for x in f[2:].split(",")])167if h == "]]":168h = Zx(0)169else:170h = Zx([int(x) for x in h[:-2].split(",")])171P = InsolublePlaces(f,h)172P = [int(p) for p in P]173c['non_solvable_places'] = P174# Former name, remove it175if 'insoluble_places' in c:176c.pop('insoluble_places')177return c178179180