Skip to content

Commit

Permalink
Merge pull request #6141 from jenpaulhus/codesnippet
Browse files Browse the repository at this point in the history
Update code snippets on group pages + add copy functionality
  • Loading branch information
jwj61 authored Aug 19, 2024
2 parents 72195f3 + 86e60bb commit ef5cd8d
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 35 deletions.
11 changes: 5 additions & 6 deletions lmfdb/groups/abstract/code.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ GLZ:
GLFp:
comment: Define the group as a matrix group with coefficients in GLFp
magma: G := MatrixGroup< {nFp}, GF({Fp}) | {LFp} >;
gap: G := not yet implemented
# gap: G := Group({LFpsplit});
gap: G := Group({LFpsplit});

GLZN:
comment: Define the group as a matrix group with coefficients in GLZN
Expand All @@ -55,10 +54,10 @@ GLZq:
gap: G := Group({LZqsplit});


#GLFq:
# comment: Define the group as a matrix group with coefficients in GLFq
# magma: G := MatrixGroup< {nFq}, GL({Fq}) | {LFq} >;
# gap: G := Group({LFqsplit});
GLFq:
comment: Define the group as a matrix group with coefficients in GLFq
magma: F:=GF({Fq}); al:=PrimitiveElement(F); G := MatrixGroup< {nFq}, F | {LFq} >;
gap: G := Group({LFqsplit});

transitive:
comment: Define the group from the transitive group database
Expand Down
100 changes: 74 additions & 26 deletions lmfdb/groups/abstract/web_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,24 @@ def split_matrix_list_ZN(longList,d, Znfld):
longList = [f"ZmodnZObj({x},{Znfld})" for x in longList]
return str([longList[i:i+d] for i in range(0,d**2,d)]).replace("'", "")

#not currently in use. Should work if elements of Fp and Fq are given as
#power of mult. generator


def split_matrix_list_Fp(longList,d,e):
return [longList[i:i+d]*e for i in range(0,d**2,d)]


def split_matrix_list_Fq(longList,d, Fqfld):
longList = [f"0*Z({Fqfld})" if x == 0 else "Z({Fqfld})^{x-1}" for x in longList]
# for gap definition of Fq
longList = [f"0*Z({Fqfld})" if x == -1 else f"Z({Fqfld})^{x}" for x in longList] #-1 distinguishes 0 from z^0
return str([longList[i:i+d] for i in range(0,d**2,d)]).replace("'", "")


def split_matrix_Fq_add_al(longList,d):
# for magma definition of Fq
longList = [0 if x == -1 else 1 if x ==0 else f"al^{x}" for x in longList]
return str([longList[i:i+d] for i in range(0,d**2,d)]).replace("'", "")


# Functions below are for conjugacy class searches
def gp_label_to_cc_data(gp):
gp_ord, gp_counter = gp.split(".")
Expand Down Expand Up @@ -1903,7 +1915,11 @@ def _matrix_coefficient_data(self, rep_type, as_str=False):
q = ZZ(rep_data["q"])
if sq_flag:
q = q**2
R = rf"\F_{{{q}}}" if as_str else GF(q)
if as_str:
R = rf"\F_{{{q}}}"
else:
R = GF(q, modulus = "primitive", names=('a',))
(a,) = R._first_ngens(1)
N, k = q.is_prime_power(get_data=True)
if k == 1:
# Might happen for Lie
Expand All @@ -1922,23 +1938,48 @@ def decode_as_matrix(self, code, rep_type, as_str=False, LieType=False, ListForm
d = rep_data["d"]
else:
R, N, k, d, rep_type = self._matrix_coefficient_data(rep_type)
if rep_type == "GLFq":
q=N**k
R = GF(q, modulus = "primitive", names=('a',))
(a,) = R._first_ngens(1) #need a for powers
L = ZZ(code).digits(N)

def pad(X, m):
return X + [0] * (m - len(L))
L = pad(L, k * d**2)
if rep_type == "GLFq":
L = [R(L[i:i+k]) for i in range(0, k*d**2, k)]
L = [l.log(a) if l!= 0 else -1 for l in L] #-1 represents 0, to distinguish from a^0
elif rep_type == "GLZ":
shift = (N - 1) // 2
L = [c - shift for c in L]
if ListForm:
return L
x = matrix(R, d, d, L)
return L #as ints representing powers of primitive element if GLFq
if rep_type == "GLFq":
x = matrix(ZZ,d,d,L) #giving powers of alpha (primitive element)
else:
x = matrix(R, d, d, L)
if as_str:
# for projective families, we add "[ ]"
if LieType and self.representations["Lie"][0]["family"][0] == "P":
return r"\left[" + latex(x) + "\\right]"
if rep_type == "GLFq": #need to customize latex command for GLFq
rs = 'r'*d
st_latex = '\left(\\begin{array}{'+rs+'}'
for i in range(d):
for j in range(d):
if j<d-1:
endstr = ' & '
else:
endstr = ' \\\ '
if L[d*i+j] >0:
st_latex =st_latex + '\\alpha^{' +str(L[d*i+j]) + '}' + endstr
elif L[d*i+j] == 0:
st_latex = st_latex+ str(1)+ endstr
else:
st_latex = st_latex+ str(0)+ endstr
st_latex=st_latex +'\end{array}\\right)'
return st_latex
return latex(x)
return x

Expand Down Expand Up @@ -2196,10 +2237,7 @@ def representation_line(self, rep_type, skip_head=False):
R, N, k, d, _ = self._matrix_coefficient_data(rep_type, as_str=True)
gens = ", ".join(self.decode_as_matrix(g, rep_type, as_str=True) for g in rdata["gens"])
gens = fr"$\left\langle {gens} \right\rangle \subseteq \GL_{{{d}}}({R})$"
if rep_type == "GLFq":
code_cmd = ""
else:
code_cmd = self.create_snippet(rep_type)
code_cmd = self.create_snippet(rep_type)
if skip_head:
return f'<tr><td></td><td colspan="5">{gens}</td></tr>{code_cmd}'
else:
Expand Down Expand Up @@ -2639,10 +2677,20 @@ def create_snippet(self,item):
else: # not currrently used in groups
lines = code[item][L]
prompt = code['prompt'][L] if 'prompt' in code and L in code['prompt'] else L
class_str = " ".join([L,'nodisplay','code','codebox'])
class_str = " ".join([L,'nodisplay','codebox'])
col_span_val = '"6"'
for line in lines:
snippet_str = snippet_str + f'<tr><td colspan={col_span_val}><div class="{class_str}"> {prompt}:&nbsp;{line}<br /><div style="margin: 0; padding: 0; height: 0;">&nbsp;</div></div></td></tr>'
snippet_str += f"""
<tr>
<td colspan={col_span_val}>
<div class="{class_str}">
<span class="raw-tset-copy-btn" onclick="copycode(this)"><img alt="Copy content" class="tset-icon"></span>
<span class="prompt">{prompt}:&nbsp;</span><span class="code">{line}</span>
<div style="margin: 0; padding: 0; height: 0;">&nbsp;</div>
</div>
</td>
</tr>
"""
return snippet_str

@cached_method
Expand Down Expand Up @@ -2679,10 +2727,10 @@ def code_snippets(self):
nFp = self.representations["GLFp"]["d"]
Fp = self.representations["GLFp"]["p"]
LFp = [self.decode_as_matrix(g, "GLFp", ListForm=True) for g in self.representations["GLFp"]["gens"]]
# LFpsplit = "[" + ",".join([split_matrix_list_Fq(self.decode_as_matrix(g, "GLFp", ListForm=True), nFp, Fp) for g in self.representations["GLFp"]["gens"]]) +"]"
e = libgap.One(GF(Fp))
LFpsplit = [split_matrix_list_Fp(A,nFp,e) for A in LFp]
else:
nFp, Fp, LFp = None, None, None
#nFp, Fp, LFp, LFpsplit = None, None, None, None
nFp, Fp, LFp, LFpsplit = None, None, None, None
if "GLZN" in self.representations:
nZN = self.representations["GLZN"]["d"]
N = self.representations["GLZN"]["p"]
Expand All @@ -2698,22 +2746,22 @@ def code_snippets(self):
else:
nZq, Zq, LZq, LZqsplit = None, None, None, None
# add below for GLFq implementation
# if "GLFq" in self.representations:
# nFq = self.representations["GLFq"]["d"]
# Fq = self.representations["GLFq"]["q"]
# LFq = [self.decode_as_matrix(g, "GLFq", ListForm=True) for g in self.representations["GLFq"]["gens"]]
# LFqsplit = "[" + ",".join([split_matrix_list_Fq(self.decode_as_matrix(g, "GLFq", ListForm=True), nFq, Fq) for g in self.representations["GLFq"]["gens"]]) +"]"
# else:
# nFq, Fq, LFq, LFqsplit = None, None, None, None
if "GLFq" in self.representations:
nFq = self.representations["GLFq"]["d"]
Fq = self.representations["GLFq"]["q"]
LFq = ",".join([split_matrix_Fq_add_al(self.decode_as_matrix(g, "GLFq", ListForm=True), nFq ) for g in self.representations["GLFq"]["gens"]])
LFqsplit = "[" + ",".join([split_matrix_list_Fq(self.decode_as_matrix(g, "GLFq", ListForm=True), nFq, Fq) for g in self.representations["GLFq"]["gens"]]) +"]"
else:
nFq, Fq, LFq, LFqsplit = None, None, None, None

data = {'gens' : gens, 'pccodelist': pccodelist, 'pccode': pccode,
'ordgp': ordgp, 'used_gens': used_gens, 'gap_assign': gap_assign,
'magma_assign': magma_assign, 'deg': deg, 'perms' : perms,
'nZ': nZ, 'nFp': nFp, 'nZN': nZN, 'nZq': nZq, #'nFq': nFq,
'Fp': Fp, 'N': N, 'Zq': Zq, #'Fq': Fq,
'LZ': LZ, 'LFp': LFp, 'LZN': LZN, 'LZq': LZq, #'LFq': LFq,
'nZ': nZ, 'nFp': nFp, 'nZN': nZN, 'nZq': nZq, 'nFq': nFq,
'Fp': Fp, 'N': N, 'Zq': Zq, 'Fq': Fq,
'LZ': LZ, 'LFp': LFp, 'LZN': LZN, 'LZq': LZq, 'LFq': LFq,
'LZsplit': LZsplit, 'LZNsplit': LZNsplit, 'LZqsplit': LZqsplit,
# 'LFpsplit': LFpsplit, 'LFqsplit': LFqsplit, # add for GLFq GAP
'LFpsplit': LFpsplit, 'LFqsplit': LFqsplit, # add for GLFq GAP
}
for prop in code:
for lang in code['prompt']:
Expand Down
9 changes: 8 additions & 1 deletion lmfdb/static/raw_typeset.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,15 @@ function copyTextOf(elt) {
);
}

function copySibling(elt, filter) {
copyTextOf($(elt).parent().children(filter).first());
}

function copyrawcontainer(elt) {
copyTextOf($(elt).parent().children("textarea.raw-container").first());
copySibling(elt, "textarea.raw-container");
}
function copycode(elt) {
copySibling(elt, "span.code");
}


Expand Down
14 changes: 12 additions & 2 deletions lmfdb/templates/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -528,12 +528,23 @@ body.intro #sidebar a.intro { background: {{ color.sidebar_bkg_highlight }}; }
height: 0px;
}

.code {
.code, .prompt {
font-family: monospace;
white-space: pre;
}

.code {
margin: 2px;
margin-right: 20px;
margin-left: 0px;
}

.prompt {
margin: 2px;
margin-right: 0px;
}


.nodisplay {
display: None;
}
Expand Down Expand Up @@ -1569,7 +1580,6 @@ div.codebox {
border-radius: 5px;
background-color: {{color.knowl_background}};
box-shadow: 3px 3px 3px {{color.knowl_shadow}};
white-space: pre;
}


Expand Down

0 comments on commit ef5cd8d

Please sign in to comment.