Skip to content

Commit db5c8b3

Browse files
committed
Added function Filter Formspace to compute Symmetric/Symplectic/Hermitian matrices: TODO: The case of characteristic two is still open for hermitian matrices and probably very poorly implemented for symmetric matrices
1 parent 6ed901a commit db5c8b3

File tree

2 files changed

+170
-26
lines changed

2 files changed

+170
-26
lines changed

lib/formspace.gd

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
# #! @Arguments matrix group, scalars, unitary
2-
# #! @Returns a basis of the formspace preserved by <A>group</A> modulo <A>scalars</A> consisting of bilinear forms if <A>unitary = false</A> and unitary forms if <A>unitary = true</>
31
DeclareOperation("PreservedFormspace", [IsMatrixGroup, IsVector and IsFFECollection, IsBool]);
2+
DeclareOperation("PreservedFormspace", [IsMatrixGroup]);
43

5-
DeclareOperation("PreservedFormspace", [IsMatrixGroup]);
4+
DeclareOperation("FilterFormspace", [IsList, IsFinite and IsField, IsBool]);

lib/formspace.gi

Lines changed: 168 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,16 @@ __FORMSPACE__INTERNAL__VectorReorganize := function(vec, j, F, n)
108108
return A;
109109
end;
110110

111+
# turns the F^{j times n} matrix into F^{jn} vector
112+
__FORMSPACE__INTERNAL__MatrixReorganize := function(mat, j, F, n)
113+
local vec, i;
114+
vec := ZeroVector(F, j*n);
115+
for i in [1..j] do
116+
vec{[((i - 1) * n + 1)..(i*n)]} := mat[i];
117+
od;
118+
return vec;
119+
end;
120+
111121
# Evaluates the univariate polynomial p (given as coefficients) in the matrix g \in F^{n\times n}. frob_base = FrobeniusNormalForm(g) must be satisfied and frob_base_inv = Inverse(FrobeniusNormalForm(g)[2]). The reason these two parameters are given, and not computed in the function itself is to not compute FrobeniusNormalForm(g) multiple times when evaluating multiple polynomials in g.
112122
__FORMSPACE__INTERNAL__EvaluatePolynomialWithFrobenius := function(p, g, frob_base, frob_base_inv, F, n) # frob_base_inv useless, right now this is not actually evaluating the polynomial frob_base_inv missing
113123
local ws, C, i, end_pos, j, k;
@@ -219,7 +229,7 @@ __FORMSPACE__INTERNAL__ScalarFormIdentifyCheck := function(Form, F, n, hom, p, q
219229
for j in [1..n] do
220230
if Form[i][j] <> Zero(F) then
221231
if Form[j][i] = Zero(F) then
222-
return [];
232+
return fail;
223233
fi;
224234
if lambda <> fail and Form[i][j] * lambda <> hom(Form[j][i]) then
225235
return fail;
@@ -234,14 +244,105 @@ __FORMSPACE__INTERNAL__ScalarFormIdentifyCheck := function(Form, F, n, hom, p, q
234244
end;
235245

236246
# find symplectic and symmetric matrices in Forms
247+
# returns bases [[symmetric forms], [symplectic forms]]
237248
__FORMSPACE__INTERNAL__FilterBilinearForms := function(Forms, F, n)
238-
# TODO
249+
local transposed_equal_result, form, symmetric_base, symplectic_base, transposed_form, TransposedEqual, symmetric_base_vecs, symplectic_base_vecs, char_2_eqs, sol, out;
250+
251+
# computes if f = f^T or f = -f^T or none
252+
# return 0 if f = -f^T
253+
# return 1 if f = f^T
254+
# return 2 if f <> f^T and f <> -f^T
255+
TransposedEqual := function(f, F, n)
256+
local i, j, symmetric_possible, symplectic_possible;
257+
258+
if Characteristic(F) mod 2 = 0 then
259+
# - = + now
260+
for i in [1..n] do
261+
for j in [1..n] do
262+
if f[i][j] <> f[j][i] then
263+
return 2;
264+
fi;
265+
od;
266+
od;
267+
return 1;
268+
fi;
269+
symmetric_possible := true;
270+
symplectic_possible := true;
271+
for i in [1..n] do
272+
for j in [1..n] do
273+
if symmetric_possible and f[i][j] <> f[j][i] then
274+
symmetric_possible := false;
275+
fi;
276+
if symplectic_possible and f[i][j] <> -f[j][i] then
277+
symplectic_possible := false;
278+
fi;
279+
od;
280+
od;
281+
if symmetric_possible then
282+
return 1;
283+
fi;
284+
if symplectic_possible then
285+
return 0;
286+
fi;
287+
return 2;
288+
end;
289+
290+
if Size(Forms) = 0 then
291+
return [];
292+
fi;
293+
if Size(Forms) = 1 then
294+
transposed_equal_result := TransposedEqual(Forms[1], F, n);
295+
if transposed_equal_result = 2 then
296+
return [];
297+
fi;
298+
if transposed_equal_result = 1 then
299+
return [[Forms[1]], []];
300+
fi;
301+
if transposed_equal_result = 2 then
302+
return [[], [Forms[1]]];
303+
fi;
304+
305+
fi;
306+
307+
if Characteristic(F) mod 2 <> 0 then
308+
symmetric_base := MutableBasis(F, [NullMat(n, n, F)]);
309+
symplectic_base := MutableBasis(F, [NullMat(n, n, F)]);
310+
for form in Forms do
311+
transposed_form := TransposedMat(form);
312+
CloseMutableBasis(symmetric_base, transposed_form + form);
313+
CloseMutableBasis(symplectic_base, form - transposed_form);
314+
od;
315+
316+
# this does not create compressed matrices, rather it returns lists consisting of compressed vectors... TODO: investigate how MutableBasis works on the inside, and maybe change it to use compressed matrices since they are faster to deal with
317+
symmetric_base_vecs := BasisVectors(ImmutableBasis(symmetric_base));
318+
symplectic_base_vecs := BasisVectors(ImmutableBasis(symplectic_base));
319+
320+
if Size(symmetric_base_vecs) + Size(symplectic_base_vecs) <> Size(Forms) then
321+
Error("This should not have happend!! there are supposedly ", Size(symmetric_base_vecs), " linearly independent symmetric forms and ", Size(symplectic_base_vecs), " linearly independent symplectic forms, yet the dimension of the formspace is ", Size(Forms), "\n");
322+
fi;
323+
return [symmetric_base_vecs, symplectic_base_vecs];
324+
325+
fi;
326+
# TODO: ignore the diagonal entries for the symmetric matrices, for symplectic these need to be zero.
327+
# TODO: solve this in some efficient way that does not formulate this by solving sets of linear equations of matrices. Instead it would be better to gradually consider entries of the matrices. Then use some heuristic to determine we are done and just check wether the resulting matrices are infact symmetric. this should be faster because now worst case we are solving a system of linear equations that consists of n^2 equations and Size(Forms) indeterminates.
328+
# TODO: maybe do these todos for all characteristics the nice thing about the current algorithm for char F <> 2 is that we do not have to solve many systems of equations, rather just check wether we have the zero matrix
329+
330+
char_2_eqs := [];
331+
for form in Forms do
332+
Add(char_2_eqs, __FORMSPACE__INTERNAL__MatrixReorganize(form - TransposedMat(form), n, F, n));
333+
od;
334+
sol := NullspaceMatDestructive(char_2_eqs);
335+
out := [];
336+
for form in sol do
337+
Add(out, __FORMSPACE__INTERNAL__VectorReorganize(form, n, F, n));
338+
od;
339+
return out;
239340
end;
240341

241342
# 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
242343
# there must be a better way to compute these matrices..
243344
__FORMSPACE__INTERNAL__FilterUnitaryForms := function(Forms, F, n, hom)
244-
local i, j, ent, q, half, O, l, FF, p, tr_form, Base, baseVecs;
345+
local i, j, ent, q, half, O, l, FF, p, tr_form, Base, baseVecs, gf_base;
245346
if Size(Forms) = 0 then
246347
return [];
247348
fi;
@@ -257,7 +358,7 @@ __FORMSPACE__INTERNAL__FilterUnitaryForms := function(Forms, F, n, hom)
257358
return [];
258359
fi;
259360

260-
return [HermitianFormByMatrix(Forms[1] * l, F)];
361+
return [Forms[1] * l];
261362
fi;
262363
# this is where it gets interesting
263364
# Print("ahhh this needs work!\n");
@@ -267,31 +368,45 @@ __FORMSPACE__INTERNAL__FilterUnitaryForms := function(Forms, F, n, hom)
267368

268369
## 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 :(
269370
## for char = 2 this can be a bad idea as it can make the diagonal disaapear.. oh well
270-
Base := MutableBasis(F, [NullMat(n, n, F)]);
271-
for FF in Forms do
272-
l := __FORMSPACE__INTERNAL__ScalarFormIdentifyCheck(FF, F, n, hom, p, q);
273-
if l = fail then
371+
if Characteristic(F) mod 2 <> 0 then
372+
Base := MutableBasis(F, [NullMat(n, n, F)]);
373+
gf_base := BasisVectors(Basis(GF(GF(q), 2)))[2];
374+
for FF in Forms do
375+
Add(FF, gf_base * FF);
376+
od;
377+
for FF in Forms do
378+
# l := __FORMSPACE__INTERNAL__ScalarFormIdentifyCheck(FF, F, n, hom, p, q);
379+
# if l = fail then
274380
tr_form := TransposedMat(FF^hom);
275381
CloseMutableBasis(Base, FF + tr_form);
276-
else
277-
CloseMutableBasis(Base, l * FF);
278-
fi;
279-
od;
382+
# else
383+
# CloseMutableBasis(Base, l * FF);
384+
# fi;
385+
od;
280386

281-
O := [];
282-
baseVecs := ImmutableBasis(Base);
283-
for FF in baseVecs do
284-
Add(O, HermitianFormByMatrix(FF, F));
285-
od;
387+
O := [];
388+
baseVecs := ImmutableBasis(Base);
389+
# for FF in baseVecs do
390+
# Add(O, HermitianFormByMatrix(FF, F));
391+
# od;
286392

287-
if Size(O) = Size(Forms) then
288-
return O;
289-
fi;
393+
# if Size(O) = Size(Forms) then
394+
# return O;
395+
# fi;
396+
# if Size(baseVecs) = Size(Forms) then
397+
# return baseVecs;
398+
# fi;
290399

291-
Print("Could not find a basis of Forms. Returned hermitian Forms, Bigger space of matrices that contains all possible hermitian forms. \n");
292-
return [O, Forms];
400+
return BasisVectors(baseVecs);
401+
fi;
402+
Print("char 2 case is missing!!");
403+
# # TODO this function definetly needs work!!!
404+
# 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");
405+
# return [baseVecs, Forms];
293406
end;
294407

408+
409+
295410
# Compute the formspace for cyclic matrix group. TODO!!
296411
__FORMSPACE__INTERNAL__CyclicGroupCase := function(Gen, Gen_adjoint_inv_scaled, Lambda, unitary, hom, frob, frob_inv_star_scaled, frob_inv_star_base_change, frob_inv_base_change, F, n)
297412
# maybe recoginize the trivial group here as a special case
@@ -399,6 +514,7 @@ __FORMSPACE__INTERNAL__FormspaceInternal := function(Gens, Lambdas, unitary, hom
399514
return O;
400515
end;
401516

517+
402518
#! @Arguments G, L, unitary
403519
#! @Returns a basis of $\mathcal{F}_h(G, \Lambda)$
404520
#! @Description
@@ -529,4 +645,33 @@ InstallMethod(PreservedFormspace,
529645
fi;
530646
return Out;
531647
end
532-
);
648+
);
649+
650+
#! @Arguments Forms, Field, unitary
651+
#! @Returns basis of the spaces of symmetric/symplectic matrices or a basis of the hermitian matrices contained in Forms
652+
#! @Description
653+
#! In the case where unitary is false, this will return a list that contains to lists of matrices. The first is a basis of the symmetric matrices, the second is a basis of the symplectic matrices. Be carefull: If the characteristic of the field is 2, then symplectic matrices and symmetric matrices are the same. Hence only one basis will be returned. If unitary is false this will return a basis of the hermitian matrices.
654+
#! The reason the the field must be given as an argument, is so that the Field automorphims of order two, which is used to compute the adjoined, is specified.
655+
InstallMethod(FilterFormspace, "for list of matrices, F finite field, bool hermitian", [IsList, IsFinite and IsField, IsBool], function(Forms, F, unitary)
656+
local n, hom, p_exponent;
657+
if Size(Forms) = 0 then
658+
return [];
659+
fi;
660+
n := NrRows(Forms[1]);
661+
662+
if Size(Forms) = n^2 then
663+
# TODO: special case where we should just return a precomputed basis...
664+
fi;
665+
666+
if not unitary then
667+
return __FORMSPACE__INTERNAL__FilterBilinearForms(Forms, F, n);
668+
else
669+
p_exponent := DegreeOverPrimeField(F);
670+
if p_exponent mod 2 <> 0 then
671+
Error("The given Field ", F, " must admit a field automorphism of order two for unitary = true\n");
672+
return [];
673+
fi;
674+
hom := FrobeniusAutomorphism(F)^(p_exponent/2);
675+
return __FORMSPACE__INTERNAL__FilterUnitaryForms(Forms, F, n, hom);
676+
fi;
677+
end);

0 commit comments

Comments
 (0)