From 8a5daa16d4fcfbc1a648eaf41dfa200d36764205 Mon Sep 17 00:00:00 2001 From: AndrewVSutherland Date: Fri, 15 Nov 2024 17:28:50 -0500 Subject: [PATCH 1/6] add inducing character search option --- lmfdb/characters/main.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lmfdb/characters/main.py b/lmfdb/characters/main.py index 793aca48b4..10c5e3226b 100644 --- a/lmfdb/characters/main.py +++ b/lmfdb/characters/main.py @@ -4,6 +4,7 @@ import re from flask import render_template, url_for, request, redirect, abort from sage.all import euler_phi, PolynomialRing, QQ, gcd, ZZ +from sage.databases.cremona import class_to_int from lmfdb.utils import ( to_dict, flash_error, SearchArray, YesNoBox, display_knowl, ParityBox, TextBox, CountBox, parse_bool, parse_ints, search_wrap, raw_typeset_poly, @@ -106,6 +107,12 @@ def __init__(self): example="2", example_span="2 or 3-5" ) + inducing = TextBox( + "inducing", + label="Induced by", + knowl="character.dirichlet.primitive", + example="3.b" + ) parity = ParityBox( "parity", knowl="character.dirichlet.parity", @@ -133,12 +140,13 @@ def __init__(self): count = CountBox() self.refine_array = [ - [modulus, conductor, order, is_real], [parity, is_primitive, is_minimal, count], + [modulus, conductor, order, inducing], [parity, is_primitive, is_minimal, is_real], [count], ] self.browse_array = [ [modulus], [conductor], [order], + [inducing], [parity], [is_primitive], [is_real], @@ -156,6 +164,24 @@ def common_parse(info, query): parse_ints(info, query, "modulus", name="modulus") parse_ints(info, query, "conductor", name="conductor") parse_ints(info, query, "order", name="order") + if 'inducing' in info: + try: + validate_label(info['inducing']) + parts_of_label = info['inducing'].split(".") + if len(parts_of_label) != 2 or not str.isalpha(parts_of_label[1]): + raise ValueError("Invalid character orbit label format, expected N.a") + primitive_modulus = int(parts_of_label[0]) + primitive_orbit = class_to_int(parts_of_label[1])+1 + if db.char_dirichlet.count({'modulus':primitive_modulus,'is_primitive':True,'orbit':primitive_orbit}) == 0: + print("hi") + raise ValueError("Primitive character orbit not found") + if 'conductor' in query: + flash_error("Conductor constraint %s ignored due to specification of primitive inducing character", info['conductor']) + query["conductor"] = primitive_modulus + query["primitive_orbit"] = primitive_orbit + except ValueError as err: + flash_error("%s is not the label of a primitive character orbit in the database, ignoring constraint", info['inducing']) + return redirect(url_for(".render_DirichletNavigation")) if 'parity' in info: parity = info['parity'] if parity == 'even': From 7e6a0e2891ae38e07cf61a59e73a31ae6f1e4f41 Mon Sep 17 00:00:00 2001 From: AndrewVSutherland Date: Sun, 17 Nov 2024 21:29:45 -0500 Subject: [PATCH 2/6] delint --- lmfdb/characters/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lmfdb/characters/main.py b/lmfdb/characters/main.py index 10c5e3226b..1416ba8f21 100644 --- a/lmfdb/characters/main.py +++ b/lmfdb/characters/main.py @@ -179,7 +179,7 @@ def common_parse(info, query): flash_error("Conductor constraint %s ignored due to specification of primitive inducing character", info['conductor']) query["conductor"] = primitive_modulus query["primitive_orbit"] = primitive_orbit - except ValueError as err: + except ValueError: flash_error("%s is not the label of a primitive character orbit in the database, ignoring constraint", info['inducing']) return redirect(url_for(".render_DirichletNavigation")) if 'parity' in info: From 6605208a73a427594c453b7dcb6bab52bb674543 Mon Sep 17 00:00:00 2001 From: AndrewVSutherland Date: Mon, 18 Nov 2024 05:54:19 -0500 Subject: [PATCH 3/6] change handling of incompatible constraints --- lmfdb/characters/main.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lmfdb/characters/main.py b/lmfdb/characters/main.py index 1416ba8f21..e8729081d2 100644 --- a/lmfdb/characters/main.py +++ b/lmfdb/characters/main.py @@ -176,9 +176,10 @@ def common_parse(info, query): print("hi") raise ValueError("Primitive character orbit not found") if 'conductor' in query: - flash_error("Conductor constraint %s ignored due to specification of primitive inducing character", info['conductor']) - query["conductor"] = primitive_modulus - query["primitive_orbit"] = primitive_orbit + query["primitive_orbit"] = 0 + else: + query["conductor"] = primitive_modulus + query["primitive_orbit"] = primitive_orbit except ValueError: flash_error("%s is not the label of a primitive character orbit in the database, ignoring constraint", info['inducing']) return redirect(url_for(".render_DirichletNavigation")) From 7449497e8f047626a1080e433b8a6634d73241dc Mon Sep 17 00:00:00 2001 From: AndrewVSutherland Date: Mon, 18 Nov 2024 08:37:14 -0500 Subject: [PATCH 4/6] remove print debugging --- lmfdb/characters/main.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/lmfdb/characters/main.py b/lmfdb/characters/main.py index e8729081d2..d5c8c9dddb 100644 --- a/lmfdb/characters/main.py +++ b/lmfdb/characters/main.py @@ -1,5 +1,3 @@ - - from lmfdb.app import app import re from flask import render_template, url_for, request, redirect, abort @@ -173,7 +171,6 @@ def common_parse(info, query): primitive_modulus = int(parts_of_label[0]) primitive_orbit = class_to_int(parts_of_label[1])+1 if db.char_dirichlet.count({'modulus':primitive_modulus,'is_primitive':True,'orbit':primitive_orbit}) == 0: - print("hi") raise ValueError("Primitive character orbit not found") if 'conductor' in query: query["primitive_orbit"] = 0 From 1e69e179624973b49ac206a0ef18662742255a73 Mon Sep 17 00:00:00 2001 From: AndrewVSutherland Date: Tue, 19 Nov 2024 00:20:03 -0500 Subject: [PATCH 5/6] more tweaks, handle inducing conrey label --- lmfdb/characters/main.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lmfdb/characters/main.py b/lmfdb/characters/main.py index d5c8c9dddb..1ba1ad0425 100644 --- a/lmfdb/characters/main.py +++ b/lmfdb/characters/main.py @@ -166,19 +166,24 @@ def common_parse(info, query): try: validate_label(info['inducing']) parts_of_label = info['inducing'].split(".") - if len(parts_of_label) != 2 or not str.isalpha(parts_of_label[1]): + if len(parts_of_label) != 2: raise ValueError("Invalid character orbit label format, expected N.a") + if not str.isalpha(parts_of_label[1]): + chi = ConreyCharacter(int(parts_of_label[0]), int(parts_of_label[1])) + label = db.char_dirichlet.lucky({'modulus': chi.modulus, 'first': chi.min_conrey_conj}, projection='label') + parts_of_label = label.split(".") primitive_modulus = int(parts_of_label[0]) primitive_orbit = class_to_int(parts_of_label[1])+1 if db.char_dirichlet.count({'modulus':primitive_modulus,'is_primitive':True,'orbit':primitive_orbit}) == 0: raise ValueError("Primitive character orbit not found") - if 'conductor' in query: + if 'conductor' in query and query['conductor'] != primitive_modulus: query["primitive_orbit"] = 0 else: query["conductor"] = primitive_modulus query["primitive_orbit"] = primitive_orbit except ValueError: - flash_error("%s is not the label of a primitive character orbit in the database, ignoring constraint", info['inducing']) + flash_error("%s is not the label of a primitive character in the database", info['inducing']) + raise ValueError return redirect(url_for(".render_DirichletNavigation")) if 'parity' in info: parity = info['parity'] From 107479639d1e470f4b5e4fb7dc81b6840cb0b413 Mon Sep 17 00:00:00 2001 From: David Roe Date: Tue, 19 Nov 2024 23:24:24 -0500 Subject: [PATCH 6/6] Fix parsing when specifying both induced character and conductor --- lmfdb/characters/main.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lmfdb/characters/main.py b/lmfdb/characters/main.py index 1ba1ad0425..d7ef1494dc 100644 --- a/lmfdb/characters/main.py +++ b/lmfdb/characters/main.py @@ -8,6 +8,7 @@ TextBox, CountBox, parse_bool, parse_ints, search_wrap, raw_typeset_poly, StatsDisplay, totaler, proportioners, comma, flash_warning, Downloader) from lmfdb.utils.interesting import interesting_knowls +from lmfdb.utils.search_parsing import parse_range3 from lmfdb.utils.search_columns import SearchColumns, MathCol, LinkCol, CheckCol, ProcessedCol, MultiProcessedCol from lmfdb.characters.utils import url_character from lmfdb.characters.TinyConrey import ConreyCharacter @@ -176,7 +177,19 @@ def common_parse(info, query): primitive_orbit = class_to_int(parts_of_label[1])+1 if db.char_dirichlet.count({'modulus':primitive_modulus,'is_primitive':True,'orbit':primitive_orbit}) == 0: raise ValueError("Primitive character orbit not found") - if 'conductor' in query and query['conductor'] != primitive_modulus: + def incompatible(query): + cond = query.get('conductor') + if cond is None: + return False + if isinstance(cond, int): + return cond != primitive_modulus + opts = parse_range3(info['conductor'], lower_bound=1, upper_bound=ORBIT_MAX_MOD) + for opt in opts: + if (isinstance(opt, int) and opt == primitive_modulus or + not isinstance(opt, int) and opt[0] <= primitive_modulus <= opt[1]): + return False + return True + if incompatible(query): query["primitive_orbit"] = 0 else: query["conductor"] = primitive_modulus @@ -184,7 +197,6 @@ def common_parse(info, query): except ValueError: flash_error("%s is not the label of a primitive character in the database", info['inducing']) raise ValueError - return redirect(url_for(".render_DirichletNavigation")) if 'parity' in info: parity = info['parity'] if parity == 'even':