Repository: LMFDB/lmfdb

Issue:
Some Dirichlet character pages are failing to load
The page https://www.lmfdb.org/Character/Dirichlet/947/934 is timing out.  Some similar pages such as https://www.lmfdb.org/Character/Dirichlet/947/933 and https://www.lmfdb.org/Character/Dirichlet/947/935 work but are slow too load and the knowl for the fixed field does not work.  I believe this is due to some of the recent changes that were made #4231 -- @BarinderBanwait can you take a look at this?

Below is the trace back from the page that is failing to load.  the failure is inside the call to "zeta_order" on line 156 of https://github.com/LMFDB/lmfdb/blob/master/lmfdb/characters/TinyConrey.py.  I don't think that call should be taking any time, but if Sage is doing something silly we should just compute zeta_order directly.  I confess it's not clear to me why we are using Sage DirichletGroup and Sage characters at all (it appears they are being used in just 2 places).

```
Traceback (most recent call last):
  File "/home/sage/sage-9.1/local/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/sage/sage-9.1/local/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/sage/sage-9.1/local/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/sage/sage-9.1/local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/home/sage/sage-9.1/local/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/sage/sage-9.1/local/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/lmfdb/lmfdb-git-web/lmfdb/characters/main.py", line 367, in render_Dirichletwebpage
    webchar = make_webchar(args)
  File "/home/lmfdb/lmfdb-git-web/lmfdb/characters/main.py", line 313, in make_webchar
    return WebDBDirichletCharacter(**args)
  File "/home/lmfdb/lmfdb-git-web/lmfdb/characters/web_character.py", line 925, in __init__
    WebDBDirichlet.__init__(self, **kwargs)
  File "/home/lmfdb/lmfdb-git-web/lmfdb/characters/web_character.py", line 568, in __init__
    self._compute()
  File "/home/lmfdb/lmfdb-git-web/lmfdb/characters/web_character.py", line 575, in _compute
    self._populate_from_db()
  File "/home/lmfdb/lmfdb-git-web/lmfdb/characters/web_character.py", line 589, in _populate_from_db
    self._set_generators_and_genvalues(values_data)
  File "/home/lmfdb/lmfdb-git-web/lmfdb/characters/web_character.py", line 615, in _set_generators_and_genvalues
    self._genvalues_for_code = get_sage_genvalues(self.modulus, self.order, vals, self.chi.sage_zeta_order(self.order))
  File "/home/lmfdb/lmfdb-git-web/lmfdb/characters/TinyConrey.py", line 156, in sage_zeta_order
    return DirichletGroup(self.modulus, base_ring=CyclotomicField(order)).zeta_order()
  File "sage/misc/cachefunc.pyx", line 2310, in sage.misc.cachefunc.CachedMethodCallerNoArgs.__call__ (build/cythonized/sage/misc/cachefunc.c:12712)
    self.cache = f(self._instance)
  File "/home/sage/sage-9.1/local/lib/python3.7/site-packages/sage/modular/dirichlet.py", line 2880, in zeta_order
    order = self.zeta().multiplicative_order()
  File "sage/rings/number_field/number_field_element.pyx", line 3229, in sage.rings.number_field.number_field_element.NumberFieldElement.multiplicative_order (build/cythonized/sage/rings/number_field/number_field_element.cpp:27976)
    elif not (self.is_integral() and self.norm().is_one()):
  File "sage/rings/number_field/number_field_element.pyx", line 3576, in sage.rings.number_field.number_field_element.NumberFieldElement.is_integral (build/cythonized/sage/rings/number_field/number_field_element.cpp:30234)
    return all(a in ZZ for a in self.absolute_minpoly())
  File "sage/rings/number_field/number_field_element.pyx", line 3576, in genexpr (build/cythonized/sage/rings/number_field/number_field_element.cpp:30109)
    return all(a in ZZ for a in self.absolute_minpoly())
  File "sage/rings/number_field/number_field_element.pyx", line 4488, in sage.rings.number_field.number_field_element.NumberFieldElement_absolute.absolute_minpoly (build/cythonized/sage/rings/number_field/number_field_element.cpp:37507)
    return self.minpoly(var)
  File "sage/rings/number_field/number_field_element.pyx", line 4576, in sage.rings.number_field.number_field_element.NumberFieldElement_absolute.minpoly (build/cythonized/sage/rings/number_field/number_field_element.cpp:38144)
    return self.charpoly(var, algorithm).radical() # square free part of charpoly
  File "sage/rings/number_field/number_field_element.pyx", line 4543, in sage.rings.number_field.number_field_element.NumberFieldElement_absolute.charpoly (build/cythonized/sage/rings/number_field/number_field_element.cpp:37945)
    return R(self.matrix().charpoly())
  File "sage/matrix/matrix_rational_dense.pyx", line 1034, in sage.matrix.matrix_rational_dense.Matrix_rational_dense.charpoly (build/cythonized/sage/matrix/matrix_rational_dense.c:10660)
    f = A.charpoly(var, algorithm=algorithm)
  File "sage/matrix/matrix_integer_dense.pyx", line 1336, in sage.matrix.matrix_integer_dense.Matrix_integer_dense.charpoly (build/cythonized/sage/matrix/matrix_integer_dense.c:12941)
    sig_on()
```


Discussion:
Just to clarify, the problem is that Sage is for some reason very slow to compute

`DirichletGroup(947,base_ring=CyclotomicField(473)).zeta_order()`

but I believe we can safely change line 156 of TinyConrey.py from

    ` return DirichletGroup(self.modulus, base_ring=CyclotomicField(order)).zeta_order()`

to

    `return 1 if self.modulus <= 2 else lcm(2,order)`

At least I have verified that this works in all cases where the modulus is less than 800.  I'm pretty sure Sage always uses roots of unity with even order except for the first and second cyclotomic fields.

But I'm still not certain that we need to or should be using sage characters at all, in which case we could just get rid of this method.  The only place they seem to be used outside of web_character.py is one place in the CMF verification code.


Resolving patch:
diff --git a/lmfdb/characters/TinyConrey.py b/lmfdb/characters/TinyConrey.py
--- a/lmfdb/characters/TinyConrey.py
+++ b/lmfdb/characters/TinyConrey.py
@@ -1,5 +1,5 @@
 from sage.all import (gcd, Mod, Integer, Integers, Rational, pari, Pari,
-                      DirichletGroup, CyclotomicField, euler_phi)
+                      DirichletGroup, CyclotomicField, euler_phi, lcm)
 from sage.misc.cachefunc import cached_method
 from sage.modular.dirichlet import DirichletCharacter
 
@@ -153,7 +153,7 @@ def gauss_sum_numerical(self, a):
         return pari("znchargauss(%s,%s,a=%d)"%(self.G,self.chi_pari,a))
 
     def sage_zeta_order(self, order):
-        return DirichletGroup(self.modulus, base_ring=CyclotomicField(order)).zeta_order()
+        return 1 if self.modulus <= 2 else lcm(2,order)
 
     def sage_character(self, order, genvalues):
         H = DirichletGroup(self.modulus, base_ring=CyclotomicField(order))


Test patch: