Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lmfdb/number_fields/test_numberfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ def test_pretty_labels(self):
self.check_args('/NumberField/4.0.2048.2', r'\Q(\sqrt{-2 + \sqrt{2}})')
self.check_args('/NumberField/8.8.3317760000.1', r'\Q(\sqrt{2}, \sqrt{3}, \sqrt{5})')
self.check_args('/NumberField/16.0.11007531417600000000.1', r'\Q(i, \sqrt{2}, \sqrt{3}, \sqrt{5})')
self.check_args('/NumberField/32.0.4026692887688564776141139207792885760000000000000000.1', r'\Q(i, \sqrt{2}, \sqrt{3}, \sqrt{5}, \sqrt{7})')

def test_signature_search(self):
# Square brackets
Expand Down
54 changes: 29 additions & 25 deletions lmfdb/number_fields/web_number_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from flask import url_for
from sage.all import (
Set, ZZ, RR, pi, gcd, euler_phi, CyclotomicField, gap, RealField, sqrt, prod, matrix, vector, GF,
Set, ZZ, RR, pi, gcd, euler_phi, CyclotomicField, gap, RealField, sqrt, prod,
QQ, NumberField, QuadraticField, PolynomialRing, latex, pari, cached_function, Permutation)

from lmfdb import db
Expand Down Expand Up @@ -263,17 +263,15 @@ def _sqrt_symbol(z):

# Case 5a: Biquadratic fields Q(\sqrt{A}, \sqrt{B})
if len(subs) == 3: # only for V_4 fields
subs = [wnf.from_coeffs(string2list(str(z[0]))) for z in subs]
# Abort if we don't know one of these fields
if not any(z._data is None for z in subs):
labels_str = [str(z.get_label()) for z in subs]
labels_split = [z.split('.') for z in labels_str]
# extract abs disc and signature to be good for sorting
labels = sorted([[integer_squarefree_part(ZZ(z[2])), - int(z[1])] for z in labels_split])
# put in +/- sign
labels_values = [z[0] * (-1)**(1 + z[1] / 2) for z in labels]
labels_str = [_sqrt_symbol(z) for z in labels_values]
return r'\(\Q(%s, %s)\)' % (labels_str[0], labels_str[1])
all_Ds = []
for sub in subs:
qs = sub[0].split(',')
all_Ds.append(integer_squarefree_part(ZZ(qs[1])**2 - 4*ZZ(qs[0])*ZZ(qs[2])))

# Sort the Ds by absolute value (in case of tie, put positive Ds first)
labels_values = sorted(all_Ds, key=lambda x: (abs(x), -x))
labels_str = [_sqrt_symbol(z) for z in labels_values]
return r'\(\Q(%s, %s)\)' % (labels_str[0], labels_str[1])

# Case 5b: Imprimitive quartic fields of type Q(\sqrt(A + B*\sqrt(D)))
if len(subs) == 1:
Expand Down Expand Up @@ -341,33 +339,39 @@ def _sqrt_symbol(z):
quad_subs = [s[0] for s in all_subs if s[0].count(',') == 2]
num_quad_subs = len(quad_subs)
if num_quad_subs == int(d) - 1:
quad_labels = [str(wnf.from_coeffs(string2list(str(z))).get_label()) for z in quad_subs]
all_Ds = [_quad_label_to_D(qlabel) for qlabel in quad_labels]
all_Ds = []
for quad_sub in quad_subs:
qs = quad_sub.split(',')
all_Ds.append(integer_squarefree_part(ZZ(qs[1])**2 - 4*ZZ(qs[0])*ZZ(qs[2])))

# Sort the Ds by absolute value (in case of tie, put positive Ds first)
sorted_Ds = sorted(all_Ds, key=lambda x: (abs(x), -x))
final_Ds = []

# Compute set of all primes dividing the Ds
primes = sorted({int(p) for D in all_Ds for p in ZZ(abs(D)).prime_divisors()})
# Compute set of all primes dividing the Ds (can take prime divisors of discriminant)
primes = ZZ(D).prime_divisors()

# Keep track of prime exponents and row space used so far
all_prime_exponents = []
row_space = matrix(GF(2), all_prime_exponents).row_space()
# Keep track of prime exponents and row space (over F_2) used so far
# For fast computations, store row_space just as a set of integers, considered as vectors of bits.
row_space = {0} # The trivial space

for D in sorted_Ds:
# Convert D to a vector of prime exponents mod 2 (including sign)
prime_exp = [int(D < 0)]+[D.valuation(p)%2 for p in primes]
if vector(prime_exp) not in row_space:
# Convert D to a vector of prime exponents mod 2 (including sign), stored with bits as an integer
# D is already squarefree, so all prime exponents either 0 or 1
prime_exp = int(D < 0)
for i in range(len(primes)):
prime_exp += int((D%primes[i]) == 0) << (i+1)
if prime_exp not in row_space:
final_Ds.append(D)

# Break out once rank is full
if len(final_Ds) == k:
break

# Recompute row space
all_prime_exponents.append(prime_exp)
row_space = matrix(GF(2), all_prime_exponents).row_space()
# Recompute the new row space (take prime_exp XOR everything else in row_space)
old_row_space = row_space.copy()
for v in old_row_space:
row_space.add(v^prime_exp) # here ^ is bitwise XOR

return r'\(\Q('+', '.join([_sqrt_symbol(D) for D in final_Ds])+r')\)'

Expand Down
Loading