Skip to content

Commit 51f3988

Browse files
committed
added char 2 case for FilterFormspace (needs work for bilinear case?) Still needs tests; removed old debug comments
1 parent 83eb172 commit 51f3988

File tree

2 files changed

+108
-59
lines changed

2 files changed

+108
-59
lines changed

lib/forms.gi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1731,7 +1731,8 @@ InstallMethod( FORMS_IsSymmetricMatrix, [IsFFECollColl],
17311731
local n, i, j;
17321732
n := NrRows(m);
17331733
for i in [1..n] do
1734-
for j in [1..i] do
1734+
# minus one to ignore diagonal entries for symmetric matrices.
1735+
for j in [1..i - 1] do
17351736
if m[i, j] <> m[j, i] then
17361737
return false;
17371738
fi;

lib/formspace.gi

Lines changed: 106 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,17 @@ FORMS_MatrixReorganize := function(mat, j, F, n)
117117
return vec;
118118
end;
119119

120+
# given j times n matrices over field F, this tries to compute a linear combination of the matrices such that their sum is zero.
121+
# todo maybe make this funciton more efficient by only considereing some equations, then considering more and so on until we are done.
122+
FORMS_SolveMatrixSystem := function(mats, j, n, F)
123+
local eqs, mat, sol, out;
124+
eqs := [];
125+
for mat in mats do
126+
Add(eqs, FORMS_MatrixReorganize(mat, j, F, n));
127+
od;
128+
return NullspaceMatDestructive(eqs);
129+
end;
130+
120131
# Spins the stuff
121132
FORMS_FrobSpin := function(Images, spin_elem, frob_base_blocks, n, F)
122133
local A, j, i, k, end_pos;
@@ -162,32 +173,22 @@ FORMS_ComputeConditionMatrixFrob := function(u, h, h_star, scalar_h, g_star_inv_
162173
local coeffs_c, coeffs_f, Ps, i, j, b_end, b_start, cpol, fpol;
163174
coeffs_c := (u * h) * frob_base_inv;
164175
coeffs_f := (u * frob_base_inv) * scalar_h;
165-
# Display(coeffs_c);
166176
j := Size(frob_base[3]);
167177
Ps := NullMat(n * j, n, F);
168178
ConvertToMatrixRep(Ps, F);
169-
# Print(frob_base[3], "\n");
170179
for i in [1..j] do
171180
if i = j then
172181
b_end := n;
173182
else
174183
b_end := frob_base[3][i + 1] - 1;
175184
fi;
176-
# Print("[", ((i - 1)*n + 1), ",", (i*n), "\n");
177-
#Print("->", frob_base[3][i],",",b_end, "\n");
185+
# this code looks horrible .... :(
178186
Ps{[((i - 1)*n + 1)..(i*n)]}{[1..n]} :=
179187
FORMS_EvaluatePolynomialWithFrobenius(coeffs_c{[frob_base[3][i]..b_end]}, g_star_inv_scaled, frob_base, frob_base_inv_star, F, n) * h_star - FORMS_EvaluatePolynomialWithFrobenius(coeffs_f{[frob_base[3][i]..b_end]}, g_star_inv_scaled, frob_base, frob_base_inv_star, F, n);
180-
# cpol := UnivariatePolynomial(F, coeffs_c);
181-
# fpol := UnivariatePolynomial(F, coeffs_f);
182-
# Ps{[((i - 1)*n + 1)..(i*n)]}{[1..n]} :=
183-
# cpol(g_star_inv_scaled) * h_star - fpol(g_star_inv_scaled);
184-
# Print(aua);
185188
od;
186189
return Ps;
187190
end;
188191

189-
190-
191192
FORMS_FrobSpinAtBlock := function(Image, spin_elem, frob_base_blocks, block_index, n, F)
192193
local A, j, i, k, end_pos;
193194
j := Size(frob_base_blocks);
@@ -230,7 +231,7 @@ end;
230231
# find symplectic and symmetric matrices in Forms
231232
# returns bases [[symmetric forms], [symplectic forms]]
232233
FORMS_FilterBilinearForms := function(Forms, F, n)
233-
local transposed_equal_result, form, symmetric_base, symplectic_base, transposed_form, TransposedEqual, symmetric_base_vecs, symplectic_base_vecs, char_2_eqs, sol, out, mat;
234+
local transposed_equal_result, form, symmetric_base, symplectic_base, transposed_form, TransposedEqual, symmetric_base_vecs, symplectic_base_vecs, char_2_eqs, sol, out, mat, tmp, i, s;
234235

235236
if Size(Forms) = 0 then
236237
return [];
@@ -257,7 +258,6 @@ FORMS_FilterBilinearForms := function(Forms, F, n)
257258
CloseMutableBasis(symplectic_base, form - transposed_form);
258259
od;
259260

260-
261261
symmetric_base_vecs := BasisVectors(ImmutableBasis(symmetric_base));
262262
symplectic_base_vecs := BasisVectors(ImmutableBasis(symplectic_base));
263263

@@ -273,20 +273,23 @@ FORMS_FilterBilinearForms := function(Forms, F, n)
273273
## TODO: this code is broken right now, FIX!! the issue seems to lie in the function FORMS_MatrixReorganize
274274
char_2_eqs := [];
275275
for form in Forms do
276-
Add(char_2_eqs, FORMS_MatrixReorganize(form - TransposedMat(form), n, F, n));
276+
Add(char_2_eqs, form - TransposedMat(form));
277277
od;
278-
sol := NullspaceMatDestructive(char_2_eqs);
279278
out := [];
280-
for form in sol do
281-
Add(out, FORMS_VectorReorganize(form, n, F, n));
279+
sol := FORMS_SolveMatrixSystem(char_2_eqs, n, n, F);
280+
for s in sol do
281+
tmp := Forms[1]*s[1];
282+
for i in [2..Size(s)] do
283+
tmp := tmp + s[i]*Forms[i];
284+
od;
285+
Add(out, tmp);
282286
od;
283287
return out;
284288
end;
285289

286-
# tries to filter the F = GF(q^2) vectorspace generated by <Forms> and return the GF(q) vector space A such that A = <Forms> \cap B where B = {A \in F^{n\times n}, A* = A} TODO: THIS NEEDS SOME FURTHER INVESTIGATION
287-
# there must be a better way to compute these matrices..
290+
# tries to filter the F = GF(q^2) vectorspace generated by <Forms> and return the GF(q) vector space A such that A = <Forms> \cap B where B = {A \in F^{n\times n}, A* = A}
288291
FORMS_FilterUnitaryForms := function(Forms, F, n, hom)
289-
local i, j, ent, q, half, O, l, FF, p, tr_form, Base, baseVecs, gf_base, hgf_base, mat;
292+
local i, j, ent, q, half, O, l, FF, p, tr_form, Base, baseVecs, gf_base, hgf_base, mat, small_field, field_aut_mat, gf_base_vecs, big_aut_mat, to_smaller_field_matrix, transpose_weird_mat, apply_aut_to_mat, eqs, s, form, form_changed, sol, out, tmp, big_field, changed_forms, apply_coefficient_and_get_smaller_matrix, square_base_entry_rep, multiply_with_scalar, form_changed_mult, form_changed_mult_star, form_changed_star;
290293
if Size(Forms) = 0 then
291294
return [];
292295
fi;
@@ -296,59 +299,111 @@ FORMS_FilterUnitaryForms := function(Forms, F, n, hom)
296299
if Size(Forms) = 1 then
297300
#checks if A = A* or A = cA* if A = A* return A, if A = cA* we want to return scalar multiples of A, namely lA for l such that c = l^(1-q) iff c^-1 = l^(q-1)
298301
# all the solutions then are lA*GF(q) is this correct?? i am not sure if this are indeed all the possible solutions, but it certanly are solutions.
299-
# Print(ff);
300302
l := FORMS_ScalarFormIdentifyCheck(Forms[1], F, n, hom, p, q);
301303
if l = fail then
302304
return [];
303305
fi;
304306

305307
return [Forms[1] * l];
306308
fi;
307-
# this is where it gets interesting
308-
# Print("ahhh this needs work!\n");
309-
# kind of okay case?
310309

311-
## TODO proof if gAg^* = cA for some c it must hold that c \in GF(q) (not in GF(q^2))
310+
## If A = A* is a form preserved modulo scalar c in GF(q^2) i.e. gAg* = cA for group elements g. then c in GF(q).
312311

313-
## we use (A + A*) is a hermitian form if gAg* = A the problem here is that for A, B such that gA*g = A and gB*g = B we may loose information namely it may be the case that 1/2 (A + A*) = c/2 (B + B*) this is annoying.... one thing one could do is check whether these matrices <1/2 (A + A*), 1/2 (B + B*), ...> are lineraly independent. if that is the case, we know that all forms must have been found (but do we???). but what if not? then there might be another form... this is annoying. Then we may add matrices A, B and so on such that <C1,C2, ., D1, D2..> is a basis of F where C1 and so on are hermitian and D1, D2 and so on are not. We may write D1 = A + B where A is hermitian and B is not. we can then try to write B in terms of the other matrices??? does this help... idk :(
314-
## for char = 2 this can be a bad idea as it can make the diagonal disaapear.. oh well
312+
## for char = 2 this can not yield all hermitian matrices as it deletes the diagonal disaapear.
315313
if p <> 2 then
316314
Base := MutableBasis(GF(q), [NullMat(n, n, GF(q))]);
317315
# Base := MutableBasis(GF(q), [], ZeroVector(GF(q), n));
318316
gf_base := BasisVectors(Basis(GF(GF(q), 2)))[2];
319317
hgf_base := hom(gf_base);
320318
for FF in Forms do
321-
# l := FORMS_ScalarFormIdentifyCheck(FF, F, n, hom, p, q);
322-
# if l = fail then
323319
tr_form := TransposedMat(FF^hom);
324320
CloseMutableBasis(Base, FF + tr_form);
325321
CloseMutableBasis(Base, gf_base * FF + hgf_base*tr_form);
326-
# else
327-
# CloseMutableBasis(Base, l * FF);
328-
# fi;
329322
od;
330323

331324
O := [];
332325
baseVecs := BasisVectors(ImmutableBasis(Base));
333-
# for FF in baseVecs do
334-
# Add(O, HermitianFormByMatrix(FF, F));
335-
# od;
336-
337-
# if Size(O) = Size(Forms) then
338-
# return O;
339-
# fi;
340-
# if Size(baseVecs) = Size(Forms) then
341-
# return baseVecs;
342-
# fi;
343-
# for mat in baseVecs do
344-
# ConvertToMatrixRep(mat, F);
345-
# od;
326+
346327
return baseVecs;
347328
fi;
348-
Print("char 2 case is missing!!");
349-
# # TODO this function definetly needs work!!!
350-
# Print("Could not find a basis of hermitian Forms. Returned hermitian Forms and a Bigger space of matrices that contains all possible hermitian forms. \n");
351-
# return [baseVecs, Forms];
329+
330+
# the idea for char 2 is to solve the semiliner system of equations. we take a F_q basis of F_q^2 namely <1, delta> and express n times n matrices with this basis.
331+
332+
# TODO: this function is potentially really slow, it would be much better two only take a few equations and constain the problem instead of taking the entire n times n matrix. One such example would be the form space preserved by G := Group(SU(200, 2^2).1) then Size(Forms) = 38420 consisting of 200x200 matrices.
333+
334+
small_field := GF(q);
335+
big_field := GF(q^2);
336+
gf_base := Basis(GF(small_field, 2));
337+
gf_base_vecs := BasisVectors(gf_base);
338+
# expresses n times n matrices as 2n times n matrices where 2 time 1 collumn vectors contain the coefficients ascoiciated with the basis gf_base
339+
to_smaller_field_matrix := function(basis_of_field, small_field_, mat, n, c)
340+
local outmat, i, j;
341+
outmat := NullMat(2 * n, c, small_field_);
342+
for i in [1..n] do
343+
for j in [1..c] do
344+
outmat{[(2*i - 1)..(2*i)]}[j] := Coefficients(basis_of_field, mat[i][j]);
345+
od;
346+
od;
347+
ConvertToMatrixRep(outmat, small_field_);
348+
return outmat;
349+
end;
350+
# this matrix applies the field automorphism hom to a element expressed in the basis over the smaller field
351+
field_aut_mat := to_smaller_field_matrix(gf_base, small_field, [[hom(gf_base_vecs[1]), hom(gf_base_vecs[2])]], 1, 2);
352+
apply_aut_to_mat := function(mat, n, aut_mat)
353+
local outmat, i, j;
354+
outmat := 1*mat; # ugly hack to force gap to make a new copy of the matrix.
355+
for i in [1..n] do
356+
for j in [1..n] do
357+
outmat{[(2*i - 1)..(2*i)]}[j] := aut_mat * outmat{[(2* i - 1)..(2*i)]}[j];
358+
od;
359+
od;
360+
return outmat;
361+
end;
362+
363+
# transposes 2n times n matrix
364+
transpose_weird_mat := function(mat, n)
365+
local outmat, i, j;
366+
outmat := 1*mat; # hack to force gap to copy the matrix.
367+
for i in [1..n] do
368+
for j in [1..n] do
369+
outmat{[(2*i-1)..(2*i)]}[j] := mat{[(2*j-1)..(2*j)]}[i];
370+
od;
371+
od;
372+
return outmat;
373+
end;
374+
375+
square_base_entry_rep := Coefficients(gf_base, gf_base_vecs[2]^2);
376+
# multiplies a 2n times n matrix over F_q with a scalar from F_q^2
377+
multiply_with_scalar := function(scalar,gf_base, square_base_entry_rep, mat, n)
378+
local smat, srep;
379+
srep := Coefficients(gf_base, scalar);
380+
smat := [[srep[1], srep[2] * square_base_entry_rep[1]],
381+
[srep[2], srep[1] + srep[2] * square_base_entry_rep[2]]];
382+
return apply_aut_to_mat(mat, n, smat);
383+
end;
384+
385+
eqs := [];
386+
# build linear equations that can now be solved over F_q
387+
for form in Forms do
388+
form_changed := to_smaller_field_matrix(gf_base, small_field, form, n, n);
389+
form_changed_star := apply_aut_to_mat(transpose_weird_mat(form_changed, n), n, field_aut_mat);
390+
form_changed_mult := multiply_with_scalar(gf_base_vecs[2], gf_base, square_base_entry_rep, form_changed, n);
391+
form_changed_mult_star := multiply_with_scalar(hom(gf_base_vecs[2]), gf_base, square_base_entry_rep, form_changed, n);
392+
393+
Add(eqs, form_changed - form_changed_star);
394+
Add(eqs, form_changed_mult - form_changed_mult_star);
395+
od;
396+
397+
sol := FORMS_SolveMatrixSystem(eqs, 2*n, n, small_field);
398+
out := [];
399+
for s in sol do
400+
tmp := (s[1]*gf_base_vecs[1] + s[2]*gf_base_vecs[2])*Forms[1];
401+
for i in [2..Size(Forms)] do
402+
tmp := tmp + (s[2*i - 1]*gf_base_vecs[1] + s[2*i]*gf_base_vecs[2])*Forms[i];
403+
od;
404+
Add(out, tmp);
405+
od;
406+
return out;
352407
end;
353408

354409
# Compute the formspace for cyclic matrix group.
@@ -414,9 +469,9 @@ FORMS_FormspaceInternal := function(Gens, Lambdas, unitary, hom, g_res, g_inv_fr
414469
fi;
415470
W := nspace;
416471
first := false;
417-
# technically we still need checking here..
418472
fi;
419473
if Size(nspace) = 1 then
474+
# technically we still need checking here..
420475
needs_checking := true;
421476
break;
422477
fi;
@@ -437,11 +492,6 @@ FORMS_FormspaceInternal := function(Gens, Lambdas, unitary, hom, g_res, g_inv_fr
437492
od;
438493
if not failed_check then
439494
Add(O, A);
440-
# if not unitary then
441-
# Add(O, BilinearFormByMatrix(A, F));
442-
# else
443-
# Add(O, A);
444-
# fi;
445495
fi;
446496
fi;
447497
if not needs_checking then
@@ -531,15 +581,13 @@ InstallMethod(PreservedFormspace,
531581
Out := [];
532582
F := DefaultFieldOfMatrixGroup(G);
533583
p_exponent := DegreeOverPrimeField(F);
534-
# Prüfen ob es sich um einen endlichen körper handelt??
584+
# Todo check if F finite?
535585
Gens := GeneratorsOfGroup(G);
536-
# F := DefaultFieldOfMatrix(Gens[1]);
537586
n := NrRows(Gens[1]);
538587
d := Size(Gens);
539588
hom := fail;
540589

541590
if d = 1 then
542-
# Todo.... !!
543591
Gen := Gens[1];
544592
Gen_adjoint := FORMS_CalculateAdjoint(Gen, false, fail, n, F);
545593
Gen_adjoint_inv_scaled := One(F)*Inverse(Gen_adjoint); # scaling happens here!!

0 commit comments

Comments
 (0)