Skip to content

Commit 61a071b

Browse files
authored
Merge pull request #6265 from LMFDB/main
main -> dev
2 parents f4bab9a + 5bd0fe0 commit 61a071b

File tree

4 files changed

+158
-27
lines changed

4 files changed

+158
-27
lines changed

lmfdb/galois_groups/transitive_group.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,3 +936,86 @@ def get_aliases():
936936
aliases[ky].append(nt)
937937
aliases[ky].sort()
938938
return aliases
939+
940+
# These dictionaries are used by number field parsing code when user requests a dihedral galois group
941+
dihedral_gal = {
942+
2: "2T1",
943+
4: "4T2",
944+
6: "6T2",
945+
8: "8T4",
946+
10: "10T2",
947+
12: "12T3",
948+
14: "14T2",
949+
16: "16T13",
950+
18: "18T5",
951+
20: "20T4",
952+
22: "22T2",
953+
24: "24T13",
954+
26: "26T2",
955+
28: "28T4",
956+
30: "30T3",
957+
32: "32T31",
958+
34: "34T2",
959+
36: "36T10",
960+
38: "38T2",
961+
40: "40T12",
962+
42: "42T5",
963+
44: "44T4",
964+
46: "46T2",
965+
}
966+
967+
dihedral_ngal = {
968+
3: "3T2",
969+
4: "4T3",
970+
5: "5T2",
971+
6: "6T3",
972+
7: "7T2",
973+
8: "8T6",
974+
9: "9T3",
975+
10: "10T3",
976+
11: "11T2",
977+
12: "12T12",
978+
13: "13T2",
979+
14: "14T3",
980+
15: "15T2",
981+
16: "16T56",
982+
17: "17T2",
983+
18: "18T13",
984+
19: "19T2",
985+
20: "20T10",
986+
21: "21T5",
987+
22: "22T3",
988+
23: "23T2",
989+
24: "24T34",
990+
25: "25T4",
991+
26: "26T3",
992+
27: "27T8",
993+
28: "28T10",
994+
29: "29T2",
995+
30: "30T14",
996+
31: "31T2",
997+
32: "32T374",
998+
33: "33T3",
999+
34: "34T3",
1000+
35: "35T4",
1001+
36: "36T47",
1002+
37: "37T2",
1003+
38: "38T3",
1004+
39: "39T4",
1005+
40: "40T46",
1006+
41: "41T2",
1007+
42: "42T11",
1008+
43: "43T2",
1009+
44: "44T9",
1010+
45: "45T4",
1011+
46: "46T3",
1012+
47: "47T2",
1013+
}
1014+
1015+
multiquad = {
1016+
2: "2T1",
1017+
4: "4T2",
1018+
8: "8T3",
1019+
16: "16T4",
1020+
32: "32T39",
1021+
}

lmfdb/number_fields/number_field.py

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
from lmfdb.utils import (
1111
web_latex, to_dict, coeff_to_poly, comma, format_percentage,
1212
flash_error, display_knowl, CountBox, Downloader, prop_int_pretty,
13-
SearchArray, TextBox, YesNoBox, YesNoMaybeBox, SubsetNoExcludeBox,
13+
SearchArray, TextBox, YesNoBox, YesNoMaybeBox, SubsetNoExcludeBox, SelectBox,
1414
SubsetBox, TextBoxWithSelect, parse_bool_unknown, parse_posints,
1515
clean_input, nf_string_to_label, parse_galgrp, parse_ints, parse_bool,
1616
parse_signed_ints, parse_primes, parse_bracketed_posints, parse_nf_string,
17-
parse_floats, parse_subfield, search_wrap, parse_padicfields,
17+
parse_floats, parse_subfield, search_wrap, parse_padicfields, integer_options,
1818
raw_typeset, raw_typeset_poly, flash_info, input_string_to_poly,
1919
raw_typeset_int, compress_poly_Q, compress_polynomial)
2020
from lmfdb.utils.web_display import compress_int
@@ -25,7 +25,8 @@
2525
cclasses_display_knowl,character_table_display_knowl,
2626
group_phrase, galois_group_data, transitive_group_display_knowl,
2727
group_cclasses_knowl_guts, group_pretty_and_nTj, knowl_cache,
28-
group_character_table_knowl_guts, group_alias_table)
28+
group_character_table_knowl_guts, group_alias_table,
29+
dihedral_gal, dihedral_ngal, multiquad)
2930
from lmfdb.number_fields import nf_page, nf_logger
3031
from lmfdb.number_fields.web_number_field import (
3132
field_pretty, WebNumberField, nf_knowl_guts, factor_base_factor,
@@ -898,7 +899,44 @@ def number_field_search(info, query):
898899
parse_posints(info,query,'relative_class_number')
899900
parse_ints(info,query,'num_ram')
900901
parse_bool(info,query,'cm_field',qfield='cm')
901-
parse_bool(info,query,'is_galois')
902+
fi = info.get("field_is")
903+
if fi == "cyc":
904+
query["gal_is_cyclic"] = True
905+
elif fi == "ab":
906+
query["gal_is_abelian"] = True
907+
elif fi in ["dih_ngal", "dih_gal", "multi_quad"]:
908+
if fi == "dih_ngal":
909+
opts = dihedral_ngal
910+
elif fi == "dih_gal":
911+
opts = dihedral_gal
912+
else:
913+
opts = multiquad
914+
if "degree" in info:
915+
opts = {n: opts[n] for n in integer_options(info["degree"], contained_in=list(opts), lower_bound=1, upper_bound=47) if n in opts}
916+
if "galois_label" in query:
917+
# Added by parse_galgrp, so we intersect with opts
918+
if isinstance(query["galois_label"], dict):
919+
ggopt = set(query["galois_label"]["$in"])
920+
else:
921+
ggopt = {query["galois_label"]}
922+
opts = {n: gg for (n, gg) in opts.items() if gg in ggopt}
923+
if len(opts) == 0:
924+
# Incompatible with specified degree or galois labels, so we add an impossible condition
925+
query["degree"] = -1
926+
elif len(opts) == 1:
927+
n, gg = list(opts.items())[0]
928+
query["degree"] = n
929+
query["galois_label"] = gg
930+
else:
931+
query["degree"] = {"$in": list(opts)}
932+
query["galois_label"] = {"$in": list(opts.values())}
933+
elif fi == "gal":
934+
query["is_galois"] = True
935+
elif fi == "solv":
936+
query["gal_is_solvable"] = True
937+
elif fi == "nsolv":
938+
query["gal_is_solvable"] = False
939+
902940
parse_bracketed_posints(info,query,'class_group',check_divisibility='increasing',process=int)
903941
parse_primes(info,query,'ur_primes',name='Unramified primes',
904942
qfield='ramps',mode='exclude')
@@ -1176,10 +1214,21 @@ def __init__(self):
11761214
knowl="nf.galois_search",
11771215
example="C5",
11781216
example_span="[8,3], 8.3, C5 or 7T2")
1179-
is_galois = YesNoBox(
1180-
name="is_galois",
1181-
label="Galois",
1182-
knowl="nf.galois_group")
1217+
field_is_opts = [
1218+
("", ""),
1219+
("cyc", "cyclic"),
1220+
("ab", "abelian"),
1221+
("multi_quad", "multi-quadratic"),
1222+
("dih_ngal", "dihedral non-Galois"),
1223+
("dih_gal", "dihedral Galois"),
1224+
("gal", "Galois"),
1225+
("solv", "solvable"),
1226+
("nsolv", "nonsolvable"),]
1227+
field_is = SelectBox(
1228+
name="field_is",
1229+
label="Field is",
1230+
knowl="nf.field_is",
1231+
options=field_is_opts)
11831232
regulator = TextBox(
11841233
name="regulator",
11851234
label="Regulator",
@@ -1259,7 +1308,7 @@ def __init__(self):
12591308
self.browse_array = [
12601309
[degree, signature],
12611310
[discriminant, rd],
1262-
[gal, is_galois],
1311+
[gal, field_is],
12631312
[num_ram, grd],
12641313
[class_number, class_group],
12651314
[ram_primes, ur_primes],
@@ -1271,13 +1320,13 @@ def __init__(self):
12711320

12721321
self.refine_array = [
12731322
[degree, signature, num_ram, ram_primes, ur_primes ],
1274-
[gal, is_galois, subfield, class_group, class_number],
1323+
[gal, field_is, subfield, class_group, class_number],
12751324
[discriminant, rd, grd, cm_field, relative_class_number],
12761325
[regulator, completion, monogenic, index, inessentialprimes],
12771326
[is_minimal_sibling]]
12781327

12791328
#[degree, signature, class_number, class_group, cm_field],
1280-
#[num_ram, ram_primes, ur_primes, gal, is_galois],
1329+
#[num_ram, ram_primes, ur_primes, gal, field_is],
12811330
#[discriminant, rd, grd, regulator, subfield],
12821331
#[completion, is_minimal_sibling, monogenic, index, inessentialprimes],
12831332
#[relative_class_number]]

lmfdb/templates/workshops.html

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,6 @@
8686

8787
<br>
8888

89-
<li>
90-
<a href="https://math.mit.edu/~edgarc/MCW2.html">Modular curves workshop 2</a>, <br>
91-
November 5-9, 2022, <a href="https://math.mit.edu/">MIT</a>,
92-
Cambridge, MA, USA <br>
93-
Sponsored by <a href="https://www.simonsfoundation.org/">Simons Foundation</a>
94-
</li>
95-
96-
<br>
97-
9889
<li>
9990
<a href="https://math.mit.edu/~edgarc/MCW2.html">Modular curves workshop 2</a>, <br>
10091
November 5-9, 2022, <a href="https://math.mit.edu/">MIT</a>,
@@ -106,7 +97,7 @@
10697

10798
<li>
10899
Improved tabulation of local fields, <br>
109-
May 23-276, 2022,
100+
May 23-27, 2022,
110101
<a href="https://aimath.org/">American Institute of
111102
Mathematics</a>, San Jose, CA, USA <br>
112103
Sponsored by <a href="https://aimath.org/">American Institute of

lmfdb/utils/search_parsing.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -380,20 +380,28 @@ def parse_range2rat(arg, key, process):
380380

381381
# We parse into a list of singletons and pairs, like [[-5,-2], 10, 11, [16,100]]
382382
# If split0, we split ranges [-a,b] that cross 0 into [-a, -1], [1, b]
383-
def parse_range3(arg, split0=False):
383+
def parse_range3(arg, split0=False, lower_bound=None, upper_bound=None):
384384
if isinstance(arg, str):
385385
arg = arg.replace(" ", "")
386386
if "," in arg:
387-
return sum([parse_range3(a, split0) for a in arg.split(",")], [])
387+
return sum([parse_range3(a, split0, lower_bound, upper_bound) for a in arg.split(",")], [])
388388
elif "-" in arg[1:]:
389389
ix = arg.index("-", 1)
390390
start, end = arg[:ix], arg[ix + 1:]
391391
if start:
392392
low = ZZ(str(start))
393+
if lower_bound is not None:
394+
low = max(low, lower_bound)
395+
elif lower_bound is not None:
396+
low = lower_bound
393397
else:
394398
raise SearchParsingError("It needs to be an integer (such as 25), a range of integers (such as 2-10 or 2..10), or a comma-separated list of these (such as 4,9,16 or 4-25, 81-121).")
395399
if end:
396400
high = ZZ(str(end))
401+
if upper_bound is not None:
402+
high = min(high, upper_bound)
403+
elif upper_bound is not None:
404+
high = upper_bound
397405
else:
398406
raise SearchParsingError("It needs to be an integer (such as 25), a range of integers (such as 2-10 or 2..10), or a comma-separated list of these (such as 4,9,16 or 4-25, 81-121).")
399407
if low == high:
@@ -413,15 +421,15 @@ def parse_range3(arg, split0=False):
413421
else:
414422
return [ZZ(str(arg))]
415423

416-
def integer_options(arg, max_opts=None, contained_in=None):
424+
def integer_options(arg, max_opts=None, contained_in=None, lower_bound=None, upper_bound=None):
417425
if not LIST_RE.match(arg) and MULT_PARSE.fullmatch(arg):
418426
# Make input work using some arithmetic expressions
419427
try:
420428
ast_expression = ast.parse(arg.replace("^", "**"), mode="eval")
421429
arg = str(int(PowMulNodeVisitor().visit(ast_expression).body))
422430
except (TypeError, ValueError, SyntaxError):
423431
raise SearchParsingError("Unable to evaluate expression.")
424-
intervals = parse_range3(arg)
432+
intervals = parse_range3(arg, lower_bound=lower_bound, upper_bound=upper_bound)
425433
check = max_opts is not None and contained_in is None
426434
if check and len(intervals) > max_opts:
427435
raise ValueError("Too many options.")
@@ -698,12 +706,12 @@ def parse_not_element_of(inp, query, qfield, parse_singleton=int):
698706
# Parses signed ints as an int and a sign the fields these are stored are passed in as qfield = (sign_field, abs_field)
699707
# see SearchParser.__call__ for actual arguments when calling
700708
@search_parser(clean_info=True, prep_ranges=True)
701-
def parse_signed_ints(inp, query, qfield, parse_one=None):
709+
def parse_signed_ints(inp, query, qfield, parse_one=None, lower_bound=None, upper_bound=None):
702710
if parse_one is None:
703711
def parse_one(x): return (int(x.sign()), int(x.abs())) if x != 0 else (1, 0)
704712
sign_field, abs_field = qfield
705713
if SIGNED_LIST_RE.match(inp):
706-
parsed = parse_range3(inp, split0=True)
714+
parsed = parse_range3(inp, split0=True, lower_bound=lower_bound, upper_bound=upper_bound)
707715
# if there is only one part, we don't need an $or
708716
if len(parsed) == 1:
709717
parsed = parsed[0]

0 commit comments

Comments
 (0)