Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

main -> dev #6000

Merged
merged 14 commits into from
Apr 21, 2024
17 changes: 13 additions & 4 deletions lmfdb/galois_groups/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
clean_input, prep_ranges, parse_bool, parse_ints, parse_galgrp,
SearchArray, TextBox, TextBoxNoEg, YesNoBox, ParityBox, CountBox,
StatsDisplay, totaler, proportioners, prop_int_pretty, Downloader,
search_wrap, redirect_no_cache)
sparse_cyclotomic_to_mathml, search_wrap, redirect_no_cache)
from lmfdb.utils.interesting import interesting_knowls
from lmfdb.utils.search_columns import SearchColumns, LinkCol, MultiProcessedCol, MathCol, CheckCol, SearchCol
from lmfdb.api import datapage
Expand All @@ -24,6 +24,7 @@
from .transitive_group import (
galois_module_knowl_guts, group_display_short,
subfield_display, resolve_display, chartable,
cclasses_display_knowl, character_table_display_knowl,
group_alias_table, WebGaloisGroup, knowl_cache)

# Test to see if this gap installation knows about transitive groups
Expand Down Expand Up @@ -261,10 +262,15 @@ def render_group_webpage(args):
if ZZ(order).is_prime():
data['ordermsg'] = "$%s$ (is prime)" % order
pgroup = len(ZZ(order).prime_factors()) < 2
if wgg.num_conjclasses() < 50:
data['cclasses'] = wgg.conjclasses()
if ZZ(order) < ZZ(10000000) and wgg.num_conjclasses() < 21:
if wgg.num_conjclasses() < 51:
data['cclasses'] = wgg.conjclasses
else:
data['cclass_knowl'] = cclasses_display_knowl(n,t)
if wgg.num_conjclasses() < 31:
data['chartable'] = chartable(n, t)
else:
data['chartable_knowl'] = character_table_display_knowl(n,t,
name="%d x %d character table"%(wgg.num_conjclasses(),wgg.num_conjclasses()))
data['gens'] = wgg.generator_string()
if n == 1 and t == 1:
data['gens'] = 'None needed'
Expand Down Expand Up @@ -323,8 +329,10 @@ def render_group_webpage(args):
data['name'] = re.sub(r'_(\d+)',r'_{\1}',data['name'])
data['name'] = re.sub(r'\^(\d+)',r'^{\1}',data['name'])
data['nilpotency'] = '$%s$' % data['nilpotency']
data['have_isom'] = wgg.have_isomorphism
if data['nilpotency'] == '$-1$':
data['nilpotency'] = ' not nilpotent'
data['dispv'] = sparse_cyclotomic_to_mathml
downloads = []
for lang in [("Magma", "magma"), ("Oscar", "oscar"), ("SageMath", "sage")]:
downloads.append(('Code to {}'.format(lang[0]), url_for(".gg_code", label=label, download_type=lang[1])))
Expand All @@ -335,6 +343,7 @@ def render_group_webpage(args):
title=title,
bread=bread,
info=data,
gp=wgg,
code=wgg.code,
properties=prop2,
friends=friends,
Expand Down
48 changes: 48 additions & 0 deletions lmfdb/galois_groups/templates/character-table.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{%- include "knowl-defs.html" -%}
{%- from "knowl-defs.html" import KNOWL with context -%}
{%- set dummy = gp.conjclasses -%}
{%- set ccs = gp.conjugacy_classes -%}
{%- if info.char_highlight -%}
<p>The row representing the character {{info.char_highlight}} is highighted below.</p>
{%- endif -%}
<table class="nowrap">
<tr>
<td></td><td></td>
{% for c in ccs %}
<td class="right">{{ c.display_knowl() | safe }}</td>
{% endfor %}
<tr>
<td></td><td>Size</td>
{% for c in ccs %}
<td class="right">{{ c.size }}</td>
{% endfor %}
</tr>
{% for p in gp.factors_of_order %}
{% set ploop = loop %}
<tr>
<td></td><td class="right">{{KNOWL('group.conjugacy_class.power_classes',"{} P".format(p))}}</td>
{% for c in ccs %}
<td class="right">{{ ccs[c['powers'][ploop.index-1]-1].label }}</td>
{% endfor %}
</tr>
{% endfor %}
<tr>
<td></td><td>{{KNOWL('group.representation.type', 'Type')}}</td>
</tr>
{% set dispv = info.dispv %}

{% for chtr in gp.characters %}
{% if chtr.label == info.char_highlight %}
<tr class="highlighted">
{% else %}
<tr>
{% endif %}
<td> {{ chtr.display_knowl() | safe }}</td>
<td class="center">{{chtr.type()}}</td>
{% set cond = chtr.cyclotomic_n %}
{% for val in chtr.values %}
<td class="right">{{ dispv(cond, val) | safe }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
41 changes: 26 additions & 15 deletions lmfdb/galois_groups/templates/gg-show-group.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@
<tr><td>{{KNOWL('gg.simple_name', title='Group')}}:<td>&nbsp;&nbsp;<td>{{info.pretty_name}}</tr>
{% endif %}
{% if info.n < 16 %}
<tr><td>{{KNOWL('gg.conway_name', title='CHM label')}}:<td>&nbsp;&nbsp;<td>${{info.name}}$</tr>
<tr><td>{{KNOWL('gg.conway_name', title='CHM label')}}:<td>&nbsp;&nbsp;<td>
{% if info.n == 1 %}
{{info.name}}
{% else %}
${{info.name}}$
{% endif %}
</tr>
{% endif %}
<tr><td>{{KNOWL('gg.parity','Parity')}}:<td>&nbsp;&nbsp;<td>{{info.parity}}
<td>{{ place_code('even') }}</td></tr>
Expand Down Expand Up @@ -64,10 +70,12 @@

{% if info.cclasses is defined %}
<table class="ntdata">
<thead><tr><td>Cycle Type</td><td>Size</td><td>Order</td><td>Representative</td></tr></thead>
<thead><tr><td>Label</td><td>Cycle Type</td><td>Size</td><td>Order</td><td>Representative</td></tr></thead>
<tbody>
{% for c in info.cclasses %}
<tr><td> ${{c[3]}}$</td>
<tr>
<td> {{c[4]}}</td>
<td> ${{c[3]}}$</td>
<td> ${{c[2]}}$</td>
<td> ${{c[1]}}$</td>
<td> ${{c[0]}}$</td>
Expand All @@ -76,8 +84,7 @@
</tbody>
</table>
{% else %}
There are {{ info.num_cc }} conjugacy classes of elements.
Data not shown.
{{ info.cclass_knowl | safe }}
{% endif %}
</p>
<p>{{ place_code('ccs') }}</p>
Expand All @@ -99,19 +106,23 @@
<tr><td class="nowrap">{{KNOWL('group.nilpotent', 'Nilpotency class')}}:<td>&nbsp;&nbsp;<td>{{info.nilpotency}}</td>
<tr><td>{{KNOWL('group.small_group_label','Label')}}:<td>&nbsp;&nbsp;<td>{{info.groupid | safe}}
<td>{{place_code('id')}}</td></tr>
</table>

<table>
<tr><td>{{KNOWL('group.complex_character_table', 'Character table')}}:
{% if info.chartable is defined %}
<td>&nbsp;&nbsp;<td>
<pre>
{{info.chartable}}
</pre>
{% if not info.wgg.can_chartable %}
<td>&nbsp;&nbsp;
<td> not computed
</table> </div> </p>
{% elif info.chartable %}
</table>
</div>
</p>
<p>
{% include 'character-table.html' %}
{% else %}
not available.
{% endif %}
<td>&nbsp;&nbsp;
<td>
{{ info.chartable_knowl | safe }}
</table> </div> </p>
{% endif %}

<p>{{place_code('char_table')}}</p>

Expand Down
115 changes: 72 additions & 43 deletions lmfdb/galois_groups/transitive_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

from lmfdb import db

from sage.all import ZZ, gap, cached_function
from sage.all import ZZ, gap, cached_function, lazy_attribute, Permutations
import os
import yaml
from flask import render_template

from lmfdb.utils import list_to_latex_matrix, integer_divisors
from lmfdb.utils import list_to_latex_matrix, integer_divisors, sparse_cyclotomic_to_mathml
from lmfdb.groups.abstract.main import abstract_group_namecache, abstract_group_display_knowl
from lmfdb.groups.abstract.web_groups import WebAbstractGroup

def knowl_cache(galois_labels=None, results=None):
"""
Expand Down Expand Up @@ -157,28 +159,76 @@ def gapgroupnt(self):
def num_conjclasses(self):
return self._data['num_conj_classes']

@lazy_attribute
def wag(self):
return WebAbstractGroup(self.abstract_label())

def have_isomorphism(self):
if self.wag.element_repr_type == "Lie":
return False
return 'isomorphism' in self._data

@lazy_attribute
def getisom(self):
# assumes isomorphism is in _data
wag = self.wag
imgs = [Permutations(self.n()).unrank(z) for z in self._data['isomorphism']]
imgs = [gap("PermList(%s)"%str(z)) for z in imgs]
return wag.G.GroupHomomorphismByImagesNC(self.gapgroupnt(), wag.G_gens(), imgs)

@lazy_attribute
def factors_of_order(self):
return [z[0] for z in list(ZZ(self.order()).factor())]

@lazy_attribute
def characters(self):
return self.wag.characters

@lazy_attribute
def conjclasses(self):
if 'conjclasses' in self._data:
return self._data['conjclasses']
g = self.gapgroupnt()
n = self.n()
gap.set('cycletype', 'function(el, n) local ct; ct := CycleLengths(el, [1..n]); ct := ShallowCopy(ct); Sort(ct); ct := Reversed(ct); return(ct); end;')
cc = g.ConjugacyClasses()
ccn = [x.Size() for x in cc]
ccc = [x.Representative() for x in cc]
wag = self.wag
self.conjugacy_classes = wag.conjugacy_classes
if int(n) == 1:
cc2 = [[1]]
cc = ['()']
self.conjugacy_classes[0].force_repr('()')
return [['()', 1, 1, '1', '1A']]
elif self.have_isomorphism() and wag.element_repr_type != "Lie":
isom = self.getisom
cc = [z.representative for z in self.conjugacy_classes]
cc1 = [wag.decode(z) for z in cc]
cc = [isom.Image(z) for z in cc1]
for j in range(len(self.conjugacy_classes)):
self.conjugacy_classes[j].force_repr(str(cc[j]))
ccn = [z.size for z in self.conjugacy_classes]
cc2 = [gap("cycletype("+str(x)+","+str(n)+")") for x in cc]
cclabels = [z.label for z in self.conjugacy_classes]
else:
cc = ccc
cc = g.ConjugacyClasses()
ccn = [x.Size() for x in cc]
cclabels = ['' for z in cc]
cc = [x.Representative() for x in cc]
cc2 = [x.cycletype(n) for x in cc]
for j in range(len(self.conjugacy_classes)):
self.conjugacy_classes[j].force_repr(' ')
cc2 = [str(x) for x in cc2]
cc2 = [re.sub(r"\[", '', x) for x in cc2]
cc2 = [re.sub(r"\]", '', x) for x in cc2]
ans = [[cc[j], ccc[j].Order(), ccn[j], cc2[j]] for j in range(len(ccn))]
self._data['conjclasses'] = ans
ans = [[cc[j], cc[j].Order(), ccn[j], cc2[j],cclabels[j]] for j in range(len(cc))]
return ans

@lazy_attribute
def can_chartable(self):
if not db.gps_groups.lookup(self.abstract_label()):
return False
return self.wag.complex_characters_known

def chartable(self):
self.conjclasses # called to load info in self
return render_template("character-table.html", gp=self,
info={'dispv': sparse_cyclotomic_to_mathml})

def sibling_bound(self):
return self._data['bound_siblings']

Expand Down Expand Up @@ -296,19 +346,17 @@ def cclasses_display_knowl(n, t, name=None):
if n==1 and t==1:
name = 'The conjugacy class representative for '
name += group_display_short(n, t)
if ncc < 50:
return '<a title = "' + name + ' [gg.conjugacy_classes.data]" knowl="gg.conjugacy_classes.data" kwargs="n=' + str(n) + '&t=' + str(t) + '">' + name + '</a>'
return name + ' are not computed'
if ncc > 5000:
return name + ' are not computed'
return '<a title = "' + name + ' [gg.conjugacy_classes.data]" knowl="gg.conjugacy_classes.data" kwargs="n=' + str(n) + '&t=' + str(t) + '">' + name + '</a>'


@cached_function
def character_table_display_knowl(n, t, name=None):
if not name:
name = 'Character table for '
name += group_display_short(n, t)
group = WebGaloisGroup.from_nt(n, t)
if ZZ(group.order()) < ZZ(10000000) and group.num_conjclasses() < 21:
return '<a title = "' + name + ' [gg.character_table.data]" knowl="gg.character_table.data" kwargs="n=' + str(n) + '&t=' + str(t) + '">' + name + '</a>'
return '<a title = "' + name + ' [gg.character_table.data]" knowl="gg.character_table.data" kwargs="n=' + str(n) + '&t=' + str(t) + '">' + name + '</a>'
return name + ' is not computed'


Expand Down Expand Up @@ -421,21 +469,8 @@ def group_cclasses_knowl_guts(n, t):

@cached_function
def group_character_table_knowl_guts(n, t):
label = base_label(n, t)
group = db.gps_transitive.lookup(label)
gname = group['name']
gname = gname.replace('=', ' = ')
if group.get('pretty', None) is not None:
gname = group['pretty']
inf = '<div>Character table for '
inf += gname
inf += '<blockquote>'
inf += '<pre>'
inf += chartable(n, t)
inf += '</pre>'
inf += '</blockquote></div>'
return(inf)

wgg = WebGaloisGroup.from_nt(n,t)
return wgg.chartable()

@cached_function
def galois_module_knowl_guts(n, t, index):
Expand Down Expand Up @@ -548,14 +583,14 @@ def group_display_inertia(code):

def cclasses(n, t):
group = WebGaloisGroup.from_nt(n,t)
if group.num_conjclasses() >= 50:
return 'not computed'
#if group.num_conjclasses() >= 50:
# return 'not computed'
html = """<div>
<table class="ntdata">
<thead><tr><td>Cycle Type</td><td>Size</td><td>Order</td><td>Representative</td></tr></thead>
<tbody>
"""
cc = group.conjclasses()
cc = group.conjclasses
for c in cc:
html += '<tr><td>' + str(c[3]) + '</td>'
html += '<td>' + str(c[2]) + '</td>'
Expand All @@ -568,13 +603,7 @@ def cclasses(n, t):


def chartable(n, t):
group = WebGaloisGroup.from_nt(n,t)
G = group.gapgroupnt()
ctable = str(G.CharacterTable().Display())
ctable = re.sub("^.*\n", '', ctable)
ctable = re.sub("^.*\n", '', ctable)
return ctable

return WebGaloisGroup.from_nt(n,t).chartable()

def group_alias_table():
aliases = get_aliases()
Expand Down
8 changes: 6 additions & 2 deletions lmfdb/groups/abstract/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2473,7 +2473,9 @@ def sub_display_knowl(label, name=None):
name = f"Subgroup {label}"
return f'<a title = "{name} [lmfdb.object_information]" knowl="lmfdb.object_information" kwargs="args={label}&func=sub_data">{name}</a>'

def cc_data(gp, label, typ="complex"):
def cc_data(gp, label, typ="complex", representative=None):
# representative allows us to use this mechanism for Galois
# group conjugacy classes as well
if typ == "rational":
wag = WebAbstractGroup(gp)
rcc = wag.conjugacy_class_divisions
Expand Down Expand Up @@ -2510,7 +2512,9 @@ def cc_data(gp, label, typ="complex"):
sub_display_knowl(centralizer, "$" + wcent.subgroup_tex + "$")
)

if wacc.representative is None:
if representative:
ans += "<br>Representative: "+representative
elif wacc.representative is None:
ans += "<br>Representative: not computed"
else:
if label == '1A':
Expand Down
Loading
Loading