|
#############################################################################
##
## enumerators.gi FinInG package
## John Bamberg
## Anton Betten
## Jan De Beule
## Philippe Cara
## Michel Lavrauw
## Max Neunhoeffer
##
## Copyright 2018 Colorado State University
## Sabancı Üniversitesi
## Università degli Studi di Padova
## Universiteit Gent
## University of St. Andrews
## University of Western Australia
## Vrije Universiteit Brussel
##
##
## Implementation stuff for enumerators of elements of polar spaces
##
#############################################################################
## 15/2/2016: We acknowledge Max Horn for sorting out and solving a problem
## with some AsList methods, causing a problem with orb 4.7.5.
#############################################################################
#############################################################################
# The enumerator functionality is quite technical. We need many tiny and less
# tiny helping functions. We go for a bottom up approach, where we first
# declare the helping functions, and then the real user stuff in the end.
#############################################################################
#############################################################################
# Very Low level help functions
# most of these (short) functions are self explanatory.
#############################################################################
#############################################################################
#F PositionNonZeroFromRight( x )
# <x> a vector
##
InstallGlobalFunction( PositionNonZeroFromRight,
function(x)
local perm;
perm := PermList( List([1..Length(x)],y->Length(x)-y+1) );
return Length(x)-PositionNonZero( Permuted(x, perm) )+1;
end );
#############################################################################
#F FG_pos( q, x ): inverse function of FG_ffenumber
# q: prime power, x element of GF(q).
##
#InstallGlobalFunction( FG_pos,
# function(q, x)
# return Position(AsList(GF(q)), x) - 1;
# end );
#
# JB (10/04/2013): Changed this slightly, but I don't think it makes a difference.
InstallGlobalFunction( FG_pos,
function(q, x)
return Position(Enumerator(GF(q)), x) - 1;
end );
#############################################################################
#F FG_div( a, b )
# a,b: integers
##
#InstallGlobalFunction( FG_div,
# function(a, b)
# return (a - (a mod b)) / b;
# end );
#############################################################################
#F FG_ffenumber( q, a )
# q: prime power, a: integer. Returns element number a, where element 0= Zero(GF(q))
# element a (<>0) = Z(q)^(a-1)
##
#InstallGlobalFunction( FG_ffenumber,
# function(q, a)
# if a = 0 then
# return 0 * Z(q);
# else
# return Z(q)^(a-1);
# fi;
# end );
#
# JB (10/04/2013). First, happy birthday Jan! A simple change to the
# method FG_ffenumber now solves the problems with enumerators. Apparently
# GAP stores the list of GF(q) elements as an attribute for GF(q) ... so we
# can simply call Enumerator(GF(q)) for the correct ordering. Otherwise, if
# this is slow, we could actually put the ordering by degree and exponent here.
# For the moment, let us just make sure that it works.
InstallGlobalFunction( FG_ffenumber,
function(q, a)
return Enumerator(GF(q))[a+1];
end );
#the next function seems never used.
#############################################################################
#F FG_unrank_GFQ( q, rk )
# q: prime power, rk: natural number
##
#InstallGlobalFunction( FG_unrank_GFQ,
# function(q, rk)
# #local Q;
# #Q := q * q;
# if rk = 0 then
# return 0*Z(q^2);
# fi;
# return Z(q^2)^(rk-1);
# end );
#the next function seems never used.
#############################################################################
#F FG_rank_GFQ( q, x )
# q: prme power, x element of GF(q)
##
#InstallGlobalFunction( FG_rank_GFQ,
# function(q, x)
# if IsZero(x) then
# return 0;
# else
# return LogFFE(x,Z(q^2))+1;
# fi;
# end );
#############################################################################
#F FG_alpha_power( q, a )
# q: prime power, a: integer
##
InstallGlobalFunction( FG_alpha_power,
function(q, a)
return Z(q^2)^a;
end );
#############################################################################
#F FG_log_alpha( q, x )
# q: prime power, x element of GF(q^2)
##
InstallGlobalFunction( FG_log_alpha,
function(q, x)
return LogFFE(x, Z(q^2));
end );
#the next function seems never used.
#############################################################################
#F FG_beta_power( q, a )
# q: prime power, a: integer
##
InstallGlobalFunction( FG_beta_power,
function(q, a)
return Z(q^2)^((q + 1) * a);
end );
#############################################################################
#F FG_log_beta( q, x )
# q: prime power, x element in GF(q^2)
##
InstallGlobalFunction( FG_log_beta,
function(q, x)
#local Q;
#Q := q * q;
return LogFFE(x,Z(q^2)^(q+1));
end );
#############################################################################
#F FG_norm_one_element( q, a )
# q: prime power, a an integer
##
InstallGlobalFunction( FG_norm_one_element,
function(q, a)
return Z(q^2)^((q - 1) * a);
end );
#############################################################################
#F FG_index_of_norm_one_element( q, x )
# q: prime power, x an element of GF(q^2)
##
InstallGlobalFunction( FG_index_of_norm_one_element,
function(q, x)
return LogFFE(x,Z(q^2)^(q-1));
end );
#############################################################################
#F PG_element_normalize( v, offset, n )
## This function takes the first nonzero element
## from the right (!) and normalises the vector v
## by this element.
##
InstallGlobalFunction( PG_element_normalize,
function(v, offset, n)
local ii, i, a, one;
one := One(v[1]);
for ii in [0..n - 1] do
i := n - 1 - ii;
a := v[offset + i];
if not IsZero(a) then
if IsOne(a) then
return;
fi;
a := a^-1;
v{[offset..i-1+offset]} := a * v{[offset..i-1+offset]};
v[offset + i] := one;
return;
fi;
od;
Error("zero vector");
end );
#############################################################################
#F FG_evaluate_hyperbolic_quadratic_form( q, v, offset, n )
# a low level way for EvaluateForm
##
InstallGlobalFunction( FG_evaluate_hyperbolic_quadratic_form,
function(q, v, offset, n)
local alpha, beta, u;
alpha := 0*Z(q);
for u in [0..n-1] do
beta := v[offset + 2 * u] * v[offset + 2 * u + 1];
alpha := alpha + beta;
od;
return alpha;
end );
#############################################################################
#F FG_evaluate_hermitian_form( q, v, offset, n )
# a low level way for EvaluateForm
##
InstallGlobalFunction(FG_evaluate_hermitian_form,
function(q, v, offset, n)
local alpha, beta, u, Q;
Q := q * q;
alpha := 0*Z(Q);
for u in [0..n-1] do
beta := v[offset + u]^(q + 1);
alpha := alpha + beta;
od;
return alpha;
end );
#############################################################################
# Anton's Enumerator:
#############################################################################
## counting functions
#############################################################################
#F FG_nb_pts_Nbar( n, q )
# n: integer, q: prime power.
##
InstallGlobalFunction( FG_nb_pts_Nbar,
function(n, q)
if n = 1 then
return q - 1;
fi;
end );
#############################################################################
#F FG_nb_pts_Nbar( n, q )
# n: integer, q: prime power.
##
InstallGlobalFunction( FG_nb_pts_S,
function(n, q)
local a;
if n = 1 then
return 2 * q - 1;
fi;
a := FG_nb_pts_S(1, q) * FG_nb_pts_S(n - 1, q);
a := a + FG_nb_pts_N(1, q) * FG_nb_pts_N1(n - 1, q);
return a;
end );
#############################################################################
#F FG_nb_pts_N( n, q )
# n: integer, q: prime power.
##
InstallGlobalFunction( FG_nb_pts_N,
function(n, q)
local a;
if n = 1 then
return (q - 1) * (q - 1);
fi;
a := FG_nb_pts_S(1, q) * FG_nb_pts_N(n - 1, q);
a := a + FG_nb_pts_N(1, q) * FG_nb_pts_S(n - 1, q);
a := a + FG_nb_pts_N(1, q) * (q - 2) * FG_nb_pts_N1(n - 1, q);
return a;
end );
#############################################################################
#F FG_nb_pts_N1( n, q )
# n: integer, q: prime power.
##
InstallGlobalFunction( FG_nb_pts_N1,
function(n, q)
local a;
if n = 1 then
return q - 1;
fi;
a := FG_nb_pts_S(1, q) * FG_nb_pts_N1(n - 1, q);
a := a + FG_nb_pts_N1(1, q) * FG_nb_pts_S(n - 1, q);
a := a + FG_nb_pts_N1(1, q) * (q - 2) * FG_nb_pts_N1(n - 1, q);
return a;
end );
#############################################################################
#F FG_nb_pts_Sbar( n, q )
# n: integer, q: prime power.
##
InstallGlobalFunction( FG_nb_pts_Sbar,
function(n, q)
local a;
if n = 1 then
return 2;
fi;
a := FG_nb_pts_Sbar(n - 1, q);
a := a + FG_nb_pts_Sbar(1, q) * FG_nb_pts_S(n - 1, q);
a := a + FG_nb_pts_Nbar(1, q) * FG_nb_pts_N1(n - 1, q);
return a;
end );
#counting functions for hermitian. to be renamed.
# June 25, 2011, Anton
#############################################################################
#F FG_herm_nb_pts_N( n, q )
# n: integer, q: prime power.
##
InstallGlobalFunction( FG_herm_nb_pts_N,
function(n, q)
local Q, a, b, c;
Q := q * q;
if n = 1 then
return Q - 1;
fi;
a := FG_herm_nb_pts_N(n - 1, q) * (Q - q - 1);
b := FG_herm_nb_pts_S(n - 1, q) * (Q - 1);
c := a + b;
return c;
end );
#############################################################################
#F FG_herm_nb_pts_S( n, q )
# n: integer, q: prime power.
##
InstallGlobalFunction( FG_herm_nb_pts_S,
function(n, q)
local a, b, c;
#Q := q * q;
if n = 1 then
return 1;
fi;
a := FG_herm_nb_pts_N(n - 1, q) * (q + 1);
b := FG_herm_nb_pts_S(n - 1, q);
c := a + b;
return c;
end );
#############################################################################
#F FG_herm_nb_pts_N1( n, q )
# n: integer, q: prime power.
##
InstallGlobalFunction( FG_herm_nb_pts_N1,
function(n, q)
local a, b, c;
#Q := q * q;
if n = 1 then
return q + 1;
fi;
a := FG_herm_nb_pts_N1(n - 1, q);
b := FG_herm_nb_pts_N1(n - 1, q) * (q - 2) * (q + 1);
c := FG_herm_nb_pts_S(n - 1, q) * (q + 1);
return a + b + c;
end );
#############################################################################
#F FG_herm_nb_pts_Sbar( n, q )
# n: integer, q: prime power.
##
InstallGlobalFunction( FG_herm_nb_pts_Sbar,
function(n, q)
local a, b;
#Q := q * q;
if n = 1 then
return 0;
fi;
a := FG_herm_nb_pts_Sbar(n - 1, q);
b := FG_herm_nb_pts_N1(n - 1, q);
return a + b;
end );
#############################################################################
# precursors of "ElementNumber" functions
#############################################################################
#############################################################################
#F FG_N1_unrank( q, v, offset, n, a )
#v: FFE vector.
##
InstallGlobalFunction( FG_N1_unrank,
function(q, v, offset, n, a)
local l, i, j, k, j1, x, y, z, yz, u, alpha, beta, gamma, one, zero;
one := Z(q)^0;
zero := 0*Z(q);
if n = 1 then
l := q - 1;
if a < l then
alpha := FG_ffenumber(q,a+1);
beta := alpha^-1;
v[offset + 0] := alpha;
v[offset + 1] := beta;
return;
fi;
Error("Error in FG_N1_unrank");
fi;
x := FG_nb_pts_S(1, q);
y := FG_nb_pts_N1(n - 1, q);
l := x * y;
if a < l then
i := QuoInt(a, y);
j := RemInt(a,y);
FG_S_unrank(q, v, offset + (n - 1) * 2, 1, i);
FG_N1_unrank(q, v, offset, n - 1, j);
return;
fi;
a := a - l;
x := FG_nb_pts_N1(1, q);
y := FG_nb_pts_S(n - 1, q);
l := x * y;
if a < l then
i := QuoInt(a, y);
j := RemInt(a, y);
FG_N1_unrank(q, v, offset + (n - 1) * 2, 1, i);
FG_S_unrank(q, v, offset, n - 1, j);
return;
fi;
a := a - l;
x := FG_nb_pts_N1(1, q);
y := q - 2;
z := FG_nb_pts_N1(n - 1, q);
yz := y * z;
l := x * yz;
if a < l then
i := QuoInt(a, yz);
j1 := RemInt(a,yz);
j := QuoInt(j1, z);
k := RemInt(j1, z);
FG_N1_unrank(q, v, offset + (n - 1) * 2, 1, i);
alpha := FG_ffenumber(q,2+j);
v[offset + 2 * (n - 1)] := alpha * v[offset + 2 * (n - 1)];
FG_N1_unrank(q, v, offset, n - 1, k);
beta := -alpha;
gamma := one + beta;
for u in [0..n-2] do
v[offset + 2 * u] := gamma * v[offset + 2 * u];
od;
return;
fi;
Error("Error in FG_N1_unrank (2)");
end );
#############################################################################
#F FG_S_unrank( q, v, offset, n, a )
#v: FFE vector.
##
InstallGlobalFunction( FG_S_unrank,
function(q, v, offset, n, a)
local l, i, j, x, y, u, alpha, beta, one, zero;
one := Z(q)^0;
zero := 0*Z(q);
if n = 1 then
if a < q then
v[offset + 0] := FG_ffenumber(q,a);
v[offset + 1] := zero;
return;
fi;
a := a - (q - 1);
if a < q then
v[offset + 0] := zero;
v[offset + 1] := FG_ffenumber(q,a);
return;
fi;
Error("Error in FG_S_unrank");
fi;
x := FG_nb_pts_S(1, q);
y := FG_nb_pts_S(n - 1, q);
l := x * y;
if a < l then
i := QuoInt(a, y);
j := RemInt(a, y);
FG_S_unrank(q, v, offset + (n - 1) * 2, 1, i);
FG_S_unrank(q, v, offset, n - 1, j);
return;
fi;
a := a - l;
x := FG_nb_pts_N(1, q);
y := FG_nb_pts_N1(n - 1, q);
l := x * y;
if a < l then
i := QuoInt(a, y);
j := RemInt(a, y);
FG_N_unrank(q, v, offset + (n - 1) * 2, 1, i);
FG_N1_unrank(q, v, offset, n - 1, j);
alpha := v[offset + 2 * (n - 1)] * v[offset + 2 * (n - 1) + 1];
beta := -alpha;
for u in [0..n-2] do
v[offset + 2 * u] := beta * v[offset + 2 * u];
od;
return;
fi;
Error("Error in FG_S_unrank (2)");
end );
#############################################################################
#F FG_Sbar_unrank( q, v, offset, n, a )
#v: FFE vector.
##
InstallGlobalFunction( FG_Sbar_unrank,
function(q, v, offset, n, a)
local l, i, j, x, y, u, alpha, beta, one, zero;
one := Z(q)^0;
zero := 0*Z(q);
if n = 1 then
if a = 0 then
v[offset + 0] := one;
v[offset + 1] := zero;
return;
fi;
if a = 1 then
v[offset + 0] := zero;
v[offset + 1] := one;
return;
fi;
Error("Error in FG_Sbar_unrank");
fi;
y := FG_nb_pts_Sbar(n - 1, q);
l := y;
if a < l then
u := n - 1;
v[offset + 2 * u] := zero;
v[offset + 2 * u + 1] := zero;
FG_Sbar_unrank(q, v, offset, n - 1, a);
return;
fi;
a := a - l;
x := FG_nb_pts_Sbar(1, q);
y := FG_nb_pts_S(n - 1, q);
l := x * y;
if a < l then
i := QuoInt(a, y);
j := RemInt(a, y);
FG_Sbar_unrank(q, v, offset + (n - 1) * 2, 1, i);
FG_S_unrank(q, v, offset, n - 1, j);
return;
fi;
a := a - l;
x := FG_nb_pts_Nbar(1, q);
y := FG_nb_pts_N1(n - 1, q);
l := x * y;
if a < l then
i := QuoInt(a, y);
j := RemInt(a, y);
FG_Nbar_unrank(q, v, offset + (n - 1) * 2, 1, i);
FG_N1_unrank(q, v, offset, n - 1, j);
alpha := v[offset + 2 * (n - 1)] * v[offset + 2 * (n - 1) + 1];
beta := -alpha;
for u in [0..n-2] do
v[offset + 2 * u] := beta * v[offset + 2 * u];
od;
return;
fi;
Error("Error in FG_Sbar_unrank (2)");
end );
#############################################################################
#F FG_Nbar_unrank( q, v, offset, n, a )
#v: FFE vector.
##
InstallGlobalFunction( FG_Nbar_unrank,
function(q, v, offset, n, a)
if n = 1 then
if a < q - 1 then
v[offset + 0] := FG_ffenumber(q,a+1);
v[offset + 1] := Z(q)^0;
return;
fi;
Error("Error in FG_Nbar_unrank");
fi;
Error("Error in FG_Nbar_unrank (2)");
end );
#############################################################################
#F FG_N_unrank( q, v, offset, n, a )
#v: FFE vector.
##
InstallGlobalFunction( FG_N_unrank,
function(q, v, offset, n, a)
local l, i, j, k, j1, x, y, z, yz, u, alpha, beta, gamma, delta, epsilon,
one, zero, w;
w := Z(q);
one := w^0;
zero := 0*w;
if n = 1 then
x := q - 1;
y := q - 1;
l := x * y;
if a < l then
i := QuoInt(a, y);
j := RemInt(a, y);
v[offset + 0] := FG_ffenumber(q,1+j);
v[offset + 1] := FG_ffenumber(q,1+i);
return;
fi;
Error("Error in FG_N_unrank");
fi;
x := FG_nb_pts_S(1, q);
y := FG_nb_pts_N(n - 1, q);
l := x * y;
if a < l then
i := QuoInt(a, y);
j := RemInt(a, y);
FG_S_unrank(q, v, offset + (n - 1) * 2, 1, i);
FG_N_unrank(q, v, offset, n - 1, j);
return;
fi;
a := a - l;
x := FG_nb_pts_N(1, q);
y := FG_nb_pts_S(n - 1, q);
l := x * y;
if a < l then
i := QuoInt(a, y);
j := RemInt(a, y);
FG_N_unrank(q, v, offset + 2 * (n - 1), 1, i);
FG_S_unrank(q, v, offset, n - 1, j);
return;
fi;
a := a - l;
x := FG_nb_pts_N(1, q);;
y := q - 2;
z := FG_nb_pts_N1(n - 1, q);
yz := y * z;
l := x * yz;
if a < l then
i := QuoInt(a, yz);
j1 := RemInt(a, yz);
j := QuoInt(j1, z);
k := RemInt(j1, z);
FG_N_unrank(q, v, offset + (n - 1) * 2, 1, i);
FG_N1_unrank(q, v, offset, n - 1, k);
alpha := w;
beta := alpha^(j + 1);
gamma := v[offset + (n - 1) * 2] * v[offset + (n - 1) * 2 + 1];
delta := -gamma;
epsilon := delta * beta;
for u in [0..n-2] do
v[offset + 2 * u] := epsilon * v[offset + 2 * u];
od;
return;
fi;
Error("Error in FG_N_unrank(2)");
end );
#######hermitian ranking stuff, new from Anton.
#############################################################################
#F FG_herm_N_unrank( q, v, offset, n, a )
#v: FFE vector.
##
InstallGlobalFunction( FG_herm_N_unrank,
function(q, v, offset, n, a)
local Q, A, coset, rk1, x, one, zero, val, coset0, rk0, m_val, log, nb, l;
Q := q * q;
one := Z(Q)^0;
zero := 0*Z(Q);
if n = 1 then
l := Q - 1;
if a < l then
x := FG_alpha_power(q, a);
v[offset + 0] := x;
return;
fi;
Error("Error in FG_herm_N_unrank");
fi;
A := Q - q - 1;
nb := FG_herm_nb_pts_N(n - 1, q);
if a < A * nb then
coset := QuoInt(a, nb);
rk1 := RemInt(a, nb);
FG_herm_N_unrank(q, v, offset, n - 1, rk1);
if coset = 0 then
v[offset + n - 1] := zero;
else
coset := coset - 1;
val := FG_evaluate_hermitian_form(q, v, offset, n - 1);
coset0 := QuoInt(coset, q + 1);
rk0 := RemInt(coset, q + 1); # here was coset mod q + 1 (i.e., without parenthesis), which is wrong, Anton 7/15/11
m_val := - val;
log := FG_log_beta(q, m_val);
if coset0 >= log then
coset0 := coset0 + 1;
fi;
v[offset + n - 1] := FG_alpha_power(q, coset0) * FG_norm_one_element(q, rk0);
fi;
else
a := a - A * nb;
nb := FG_herm_nb_pts_S(n - 1, q);
rk1 := RemInt(a, nb);
coset := QuoInt(a, nb);
FG_herm_S_unrank(q, v, offset, n - 1, rk1);
v[offset + n - 1] := FG_alpha_power(q, coset);
fi;
end );
#############################################################################
#F FG_herm_N_rank( q, v, offset, n )
#v: FFE vector.
##
InstallGlobalFunction( FG_herm_N_rank,
function(q, v, offset, n)
local Q, rk, val, m_val, alpha, A, rk1, coset, a, coset0, rk0, beta, nb, log;
Q := q * q;
if n = 1 then
alpha := v[offset + 0];
rk := FG_log_alpha(q, alpha);
return rk;
fi;
val := FG_evaluate_hermitian_form(q, v, offset, n - 1);
nb := FG_herm_nb_pts_N(n - 1, q);
if not IsZero(val) then
rk1 := FG_herm_N_rank(q, v, offset, n - 1);
if IsZero(v[offset + n - 1]) then
coset := 0;
else
m_val := -val;
log := FG_log_beta(q, m_val);
a := v[offset + n - 1]^(q + 1);
coset0 := FG_log_beta(q, a);
beta := v[offset + n - 1] * FG_alpha_power(q, coset0)^-1;
if coset0 > log then
coset0 := coset0 - 1;
fi;
rk0 := FG_index_of_norm_one_element(q, beta);
coset := coset0 * (q + 1) + rk0;
coset := coset + 1;
fi;
rk := coset * nb + rk1;
else
A := Q - q - 1;
rk := A * nb;
coset := FG_log_alpha(q, v[offset + n - 1]);
rk1 := FG_herm_S_rank(q, v, offset, n - 1);
rk := rk + coset * FG_herm_nb_pts_S(n - 1, q) + rk1;
fi;
return rk;
end );
#############################################################################
#F FG_herm_S_unrank( q, v, offset, n, a )
#v: FFE vector.
##
InstallGlobalFunction( FG_herm_S_unrank,
function(q, v, offset, n, rk)
local Q, zero, nb, coset, rk1, log, val, m_val;
Q := q * q;
zero := 0*Z(Q);
if n = 1 then
v[offset + 0] := zero;
return;
fi;
nb := FG_herm_nb_pts_N(n - 1, q);
if rk < (q + 1) * nb then
coset := QuoInt(rk, nb);
rk1 := RemInt(rk, nb);
FG_herm_N_unrank(q, v, offset, n - 1, rk1);
val := FG_evaluate_hermitian_form(q, v, offset, n - 1);
m_val := - val;
log := FG_log_beta(q, m_val);
v[offset + n - 1] := FG_alpha_power(q, log) * FG_norm_one_element(q, coset);
else
rk := rk - (q + 1) * nb;
FG_herm_S_unrank(q, v, offset, n - 1, rk);
v[offset + n - 1] := zero;
fi;
end );
#############################################################################
#F FG_herm_S_rank( q, v, offset, n )
#v: FFE vector.
##
InstallGlobalFunction( FG_herm_S_rank,
function(q, v, offset, n)
local val, rk, rk1, m_val, log, a, log1, nb, coset;
if n = 1 then
return 0;
fi;
rk := 0;
if not IsZero(v[offset + n - 1]) then
rk1 := FG_herm_N_rank(q, v, offset, n - 1);
val := FG_evaluate_hermitian_form(q, v, offset, n - 1);
m_val := - val;
log := FG_log_beta(q, m_val);
a := v[offset + n - 1]^(q + 1);
log1 := FG_log_beta(q, a);
if log1 <> log then
Error("Error in hermitian::FG_S_rank fatal: log1 != log");
fi;
a := v[offset + n - 1] * FG_alpha_power(q, log)^-1;
coset := FG_index_of_norm_one_element(q, a);
nb := FG_herm_nb_pts_N(n - 1, q);
rk := coset * nb + rk1;
else
nb := FG_herm_nb_pts_N(n - 1, q);
rk := FG_herm_S_rank(q, v, offset, n - 1);
rk := rk + (q + 1) * nb;
fi;
return rk;
end );
#############################################################################
#F FG_herm_N1_unrank( q, v, offset, n, rk )
#v: FFE vector.
##
InstallGlobalFunction( FG_herm_N1_unrank,
function(q, v, offset, n, rk)
local Q, i, one, zero, nb, rk1, rk2, coset, coset1, coset2, nb1, a, val, new_val, log, A;
Q := q * q;
one := Z(Q)^0;
zero := 0*Z(Q);
if n = 1 then
v[offset + 0] := FG_norm_one_element(q, rk);
return;
fi;
nb := FG_herm_nb_pts_N1(n - 1, q);
if rk < nb then
FG_herm_N1_unrank(q, v, offset, n - 1, rk);
v[offset + n - 1] := zero;
return;
else
rk := rk - nb;
A := (q + 1) * (q - 2) * nb;
if rk < A then
nb1 := (q - 2) * nb;
coset1 := QuoInt(rk, nb1);
rk1 := RemInt(rk, nb1);
coset2 := QuoInt(rk1, nb);
rk2 := RemInt(rk1, nb);
FG_herm_N1_unrank(q, v, offset, n - 1, rk2);
val := FG_evaluate_hermitian_form(q, v, offset, n - 1);
coset2 := coset2 + 1;
a := FG_alpha_power(q, coset2);
for i in [0 .. n - 2] do
v[offset + i] := a * v[offset + i];
od;
val := FG_evaluate_hermitian_form(q, v, offset, n - 1);
new_val := one - val;
log := FG_log_beta(q, new_val);
v[offset + n - 1] := FG_alpha_power(q, log) * FG_norm_one_element(q, coset1);
else
rk := rk - A;
nb := FG_herm_nb_pts_S(n - 1, q);
coset := QuoInt(rk, nb);
rk1 := RemInt(rk, nb);
FG_herm_S_unrank(q, v, offset, n - 1, rk1);
v[offset + n - 1] := FG_norm_one_element(q, coset);
fi;
fi;
end );
#############################################################################
#F FG_herm_N1_rank( q, v, offset, n )
#v: FFE vector.
##
InstallGlobalFunction( FG_herm_N1_rank,
function(q, v, offset, n)
local Q, one, val, rk, rk1, nb, nb1, A, coset, coset1, coset2, a, av, i, new_val, log, rk2, log1;
Q := q * q;
one := Z(Q)^0;
if n = 1 then
return FG_index_of_norm_one_element(q, v[offset + 0]);
fi;
rk := 0;
if IsZero(v[offset + n - 1]) then
rk := FG_herm_N1_rank(q, v, offset, n - 1);
return rk;
fi;
nb := FG_herm_nb_pts_N1(n - 1, q);
rk := nb;
nb1 := (q - 2) * nb;
A := (q + 1) * nb1;
val := FG_evaluate_hermitian_form(q, v, offset, n - 1);
if not IsZero(val) then
coset2 := FG_log_beta(q, val);
a := FG_alpha_power(q, coset2);
av := a^(-1);
for i in [0 .. n - 2] do
v[offset + i] := av * v[offset + i];
od;
rk2 := FG_herm_N1_rank(q, v, offset, n - 1);
coset2 := coset2 - 1;
new_val := one - val;
log := FG_log_beta(q, new_val);
a := v[offset + n - 1]^(q + 1);
log1 := FG_log_beta(q, a);
a := FG_alpha_power(q, log)^(-1);
a := a * v[offset + n - 1];
coset1 := FG_index_of_norm_one_element(q, a);
rk1 := coset2 * nb + rk2;
rk := rk + coset1 * nb1 + rk1;
else
rk := rk + A;
rk1 := FG_herm_S_rank(q, v, offset, n - 1);
coset := FG_index_of_norm_one_element(q, v[offset + n - 1]);
rk := rk + coset * FG_herm_nb_pts_S(n - 1, q) + rk1;
fi;
return rk;
end );
#############################################################################
#F FG_herm_Sbar_unrank( q, v, offset, n, rk )
#v: FFE vector.
##
InstallGlobalFunction( FG_herm_Sbar_unrank,
function(q, v, offset, n, rk)
local Q, one, zero, a, b, log, nb, i;
Q := q * q;
one := Z(Q)^0;
zero := 0*Z(Q);
if n = 1 then
Error("FG_herm_Sbar_unrank error: n = 1");
fi;
nb := FG_herm_nb_pts_Sbar(n - 1, q);
if rk < nb then
FG_herm_Sbar_unrank(q, v, offset, n - 1, rk);
v[offset + n - 1] := zero;
else
rk := rk - nb;
FG_herm_N1_unrank(q, v, offset, n - 1, rk);
a := - one;
log := FG_log_beta(q, a);
b := FG_alpha_power(q, log);
for i in [0..n - 2] do
v[offset + i] := v[offset + i] * b;
od;
v[offset + n - 1] := one;
fi;
end );
#############################################################################
#F FG_herm_Sbar_rank( q, v, offset, n )
#v: FFE vector.
##
InstallGlobalFunction( FG_herm_Sbar_rank,
function(q, v, offset, n)
local Q, one, val, rk, rk0, nb, i, a, b, bv, log;
Q := q * q;
one := Z(Q)^0;
if n = 1 then
Error("FG_herm_Sbar_rank error: n = 1");
fi;
if IsZero(v[offset + n - 1]) then
rk := FG_herm_Sbar_rank(q, v, offset, n - 1);
else
#my_PG_element_normalize(v, offset, n);
PG_element_normalize(v, offset, n);
nb := FG_herm_nb_pts_Sbar(n - 1, q);
rk := nb;
val := FG_evaluate_hermitian_form(q, v, offset, n - 1);
a := - one;
if val <> a then
Error("FG_herm_Sbar_rank error: val <> -1");
fi;
log := FG_log_beta(q, a);
b := FG_alpha_power(q, log);
bv := b^(-1);
for i in [0 .. n - 2] do
v[offset + i] := bv * v[offset + i];
od;
val := FG_evaluate_hermitian_form(q, v, offset, n - 1);
if not IsOne(val) then
Error("FG_herm_Sbar_rank not IsOne(val)");
fi;
rk0 := FG_herm_N1_rank(q, v, offset, n - 1);
rk := rk + rk0;
fi;
return rk;
end );
#############################################################################
#F FG_S_rank( q, v, offset, n )
#v: FFE vector.
##
InstallGlobalFunction( FG_S_rank,
function(q, v, offset, n)
local a, l, i, j, x, y, u, alpha, beta, gamma, delta, epsilon;
if n = 1 then
if IsZero(v[offset + 1]) then
a := FG_pos(q, v[offset + 0]);
return a;
fi;
a := q - 1;
a := a + FG_pos(q, v[offset + 1]);
return a;
fi;
x := FG_nb_pts_S(1, q);
y := FG_nb_pts_S(n - 1, q);
l := x * y;
alpha := v[offset + 2 * (n - 1)] * v[offset + 2 * (n - 1) + 1];
if IsZero(alpha) then
i := FG_S_rank(q, v, offset + 2 * (n - 1), 1);
j := FG_S_rank(q, v, offset, n - 1);
a := i * y + j;
return a;
fi;
a := l;
y := FG_nb_pts_N1(n - 1, q);
i := FG_N_rank(q, v, offset + 2 * (n - 1), 1);
beta := -alpha;
delta := beta^-1; # JB 18/08/2014: Found a bug here and fixed it
for u in [0..n-2] do
v[offset + 2 * u] := delta * v[offset + 2 * u];
od;
j := FG_N1_rank(q, v, offset, n - 1);
a := a + i * y + j;
return a;
end );
#############################################################################
#F FG_N_rank( q, v, offset, n )
#v: FFE vector.
##
InstallGlobalFunction( FG_N_rank,
function(q, v, offset, n)
local a, l, i, j, k, x, y, z, yz, u, alpha, beta, one,
gamma, delta, epsilon, gamma2, epsilon_inv;
one := Z(q)^0;
if n = 1 then
y := q - 1;
j := FG_pos(q,v[offset + 0]) - 1;
i := FG_pos(q, v[offset + 1]) - 1;
###### a := FG_ffenumber(q, i * y + j); # JB: 18/08/2014, found the bug here ####
a := i * y + j; # it was hard to find!
return a;
fi;
gamma := v[offset + 2 * (n - 1)] * v[offset + 2 * (n - 1) + 1];
x := FG_nb_pts_S(1, q);
y := FG_nb_pts_N(n - 1, q);
l := x * y;
if IsZero(gamma) then
i := FG_S_rank(q, v, offset + 2 * (n - 1), 1);
j := FG_N_rank(q, v, offset, n - 1);
a := i * y + j;
return a;
fi;
a := l;
x := FG_nb_pts_N(1, q);
y := FG_nb_pts_S(n - 1, q);
l := x * y;
gamma2 := FG_evaluate_hyperbolic_quadratic_form(q, v, offset, n - 1);
if IsZero(gamma2) then
i := FG_N_rank(q, v, offset + 2 * (n - 1), 1);
j := FG_S_rank(q, v, offset, n - 1);
a := a + i * y + j;
fi;
a := a + l;
x := FG_nb_pts_N(1, q);
y := q - 2;
z := FG_nb_pts_N1(n - 1, q);
yz := y * z;
l := x * yz;
i := FG_N_rank(q, v, offset + 2 * (n - 1), 1);
alpha := Z(q);
delta := -gamma;
for j in [0..q-3] do
beta := alpha^(j + 1);
epsilon := delta * beta;
if epsilon = gamma2 then
epsilon_inv := epsilon^-1;
for u in [0..n-2] do
v[offset + 2 * u] := epsilon_inv * v[offset + 2 * u];
od;
k := FG_N1_rank(q, v, offset, n - 1);
a := a + i * yz + j * z + k;
return a;
fi;
od;
end );
#############################################################################
#F FG_N1_rank( q, v, offset, n )
#v: FFE vector.
##
InstallGlobalFunction( FG_N1_rank,
function(q, v, offset, n)
local a, l, i, j, k, x, y, z, yz, u, alpha,
alpha_inv, beta, gamma, gamma2, gamma_inv;
if n = 1 then
alpha := v[offset + 0];
# beta := v[offset + 1];
# gamma := alpha^-1;
a := FG_pos(q, alpha) - 1;
return a;
fi;
a := 0;
alpha := v[offset + 2 * (n - 1)] * v[offset + 2 * (n - 1) + 1];
x := FG_nb_pts_S(1, q);
y := FG_nb_pts_N1(n - 1, q);
l := x * y;
if IsZero(alpha) then
i := FG_S_rank(q, v, offset + 2 * (n - 1), 1);
j := FG_N1_rank(q, v, offset, n - 1);
a := i * y + j;
return a;
fi;
a := a + l;
gamma2 := FG_evaluate_hyperbolic_quadratic_form(q, v, offset, n - 1);
x := FG_nb_pts_N1(1, q);
y := FG_nb_pts_S(n - 1, q);
l := x * y;
if IsZero(gamma2) then
i := FG_N1_rank(q, v, offset + 2 * (n - 1), 1);
j := FG_S_rank(q, v, offset, n - 1);
a := a + i * y + j;
return a;
fi;
a := a + l;
x := FG_nb_pts_N1(1, q);
y := q - 2;
z := FG_nb_pts_N1(n - 1, q);
yz := y * z;
l := x * yz;
alpha := v[offset + 2 * (n - 1)] * v[offset + 2 * (n - 1) + 1];
j := FG_pos(q,alpha) - 2;
alpha_inv := alpha^-1;
v[offset + 2 * (n - 1)] := alpha_inv * v[offset + 2 * (n - 1)];
i := FG_N1_rank(q, v, offset + 2 * (n - 1), 1);
gamma2 := FG_evaluate_hyperbolic_quadratic_form(q, v, offset, n - 1);
gamma_inv := gamma2^-1;
for u in [0..n-2] do
v[offset + 2 * u] := gamma_inv * v[offset + 2 * u];
od;
k := FG_N1_rank(q, v, offset, n - 1);
a := a + i * yz + j * z + k;
return a;
end );
#############################################################################
#F FG_Sbar_rank( q, v, offset, n )
#v: FFE vector.
##
InstallGlobalFunction( FG_Sbar_rank,
function(q, v, offset, n)
local a, l, i, j, x, y, u, alpha, beta, beta_inv;
PG_element_normalize(v, offset, 2 * n);
if n = 1 then
if IsOne(v[offset + 0]) and IsZero(v[offset + 1]) then
a := 0;
return a;
fi;
if IsZero(v[offset + 0]) and IsOne(v[offset + 1]) then
a := 1;
return a;
fi;
fi;
a := 0;
if IsZero(v[offset + 2 * (n - 1)]) and IsZero(v[offset + 2 * (n - 1) + 1]) then
a := FG_Sbar_rank(q, v, offset, n - 1);
return a;
fi;
l := FG_nb_pts_Sbar(n - 1, q);
a := a + l;
alpha := v[offset + 2 * (n - 1)] * v[offset + 2 * (n - 1) + 1];
x := FG_nb_pts_Sbar(1, q);
y := FG_nb_pts_S(n - 1, q);
l := x * y;
if IsZero(alpha) then
i := FG_Sbar_rank(q, v, offset + 2 * (n - 1), 1);
j := FG_S_rank(q, v, offset, n - 1);
a := a + i * y + j;
return a;
fi;
a := a + l;
x := FG_nb_pts_Nbar(1, q);
y := FG_nb_pts_N1(n - 1, q);
i := FG_Nbar_rank(q, v, offset + 2 * (n - 1), 1);
beta := -alpha;
beta_inv := beta^-1;
for u in [0..n-2] do
v[offset + 2 * u] := beta_inv * v[offset + 2 * u];
od;
j := FG_N1_rank(q, v, offset, n - 1);
a := a + i * y + j;
return a;
end );
#############################################################################
#F FG_Nbar_rank( q, v, offset, n )
#v: FFE vector.
##
InstallGlobalFunction( FG_Nbar_rank,
function(q, v, offset, n)
return FG_pos(q,v[offset + 0]) - 1;
end );
#############################################################################
# Low level ElementNumber/NumberElement functions (I left these currently as operations
# in case an extra debug round would be necessary, this could be useful).
#############################################################################
#############################################################################
#F QElementNumber( d, q, a ) returns element number a of Q(d,q), see below.
##
InstallGlobalFunction( QElementNumber,
function(d, q, a)
## Anton uses the bilinear form (for the 4 dimensional case)
# 0 1 0 0 0
# 1 0 0 0 0
# 0 0 0 1 0
# 0 0 1 0 0
# 0 0 0 0 2
## Need to change form to canonical. We use the form
# 2 0 0 0 0
# 0 0 1 0 0
# 0 1 0 0 0
# 0 0 0 0 1
# 0 0 0 1 0
## So we just permute the result by a cycle. Later we should just
## change the code so that we do not need this overhead.
#
## Anton's code considers lists which begin at 0, and not at 1.
## So we need to make an adjustment for that.
local n, x, i, one, zero, v, a2, cyc;
cyc := PermList( Concatenation([2..d+1], [1]));
one := Z(q)^0;
zero := 0*Z(q);
a2 := a - 1;
v := List([1..d+1], i -> zero);
n := d / 2;
x := FG_nb_pts_Sbar(n, q);
if a2 < x then
FG_Sbar_unrank(q, v, 1, n, a2);
return Permuted(v,cyc);
fi;
a2 := a2 - x;
v[1 + 2 * n] := one;
FG_N1_unrank(q, v, 1, n, a2);
if IsOddInt(q) then
for i in [0..n-1] do
v[1 + 2 * i] := -v[1 + 2 * i];
od;
fi;
return Permuted(v,cyc);
end );
#############################################################################
#F QplusElementNumber( d, q, a ) returns element number a of Q+(d,q), see below.
##
InstallGlobalFunction( QplusElementNumber,
function(d, q, a)
# The quadratic form here is simply the
# "sums of hyperbolic pairs" form x1x2 + x3x4 +...
# In this case, we do not need to permute the
# result as there is no anisotropic part.
local n, v, i, zero, a2;
zero := 0*Z(q);
a2 := a - 1;
v := List([1..d+1], i -> zero);
n := (d+1) / 2;
FG_Sbar_unrank(q, v, 1, n, a2);
return v;
end );
#############################################################################
#F QminusElementNumber( d, q, a ) returns element number a of Q-(d,q), see below.
##
InstallGlobalFunction( QminusElementNumber,
function(d, q, a)
local n, x, i, one, zero, v, w, a2, form, c1, c2, c3,
b, c, minusz, x1, x2, u, vv, wprim, z, perm;
# The quadratic form here is
# "sums of hyperbolic pairs" form x1x2 + x3x4 +...
# plus c1 x_{2n}^2 + c2 x_{2n}x_{2n+1} + c3 x_{2n+1}^2
#
# The canonical form in FinInG has the anisotropic part
# of an elliptic quadric in the first two coordinates. Thus
# we simply apply a double transposition to the coordinates
# so that Anton's form is the same as ours.
perm := (1,d)(2,d+1);
# Choose [c1, c2, c3] compatible with FinInG:
if IsEvenInt(q) then
form := QuadraticForm( EllipticQuadric(d, q) )!.matrix;
else
form := SesquilinearForm( EllipticQuadric(d, q) )!.matrix;
fi;
c1 := form[1][1];
c2 := form[1][2];
c3 := form[2][2];
wprim := Z(q);
one := wprim^0;
zero := 0*wprim;
a2 := a - 1;
v := List([1..d+1], i -> zero);
n := (d-1) / 2;
x := FG_nb_pts_Sbar(n, q);
if a2 < x then
v[1 + 2 * n] := zero;
v[1 + 2 * n + 1] := zero;
FG_Sbar_unrank(q, v, 1, n, a2);
return Permuted(v, perm);
fi;
a2 := a2 - x;
x := FG_nb_pts_N1(n, q);
b := QuoInt(a2, x);
c := RemInt(a2, x);
if IsZero(b) then
x1 := one;
x2 := zero;
else
b := b - 1;
x1 := FG_ffenumber(q, b);
x2 := one;
fi;
v[1 + 2 * n] := x1;
v[1 + 2 * n + 1] := x2;
u := x1 * x1;
u := c1 * u; # different to Anton's code
vv := x1 * x2;
vv := c2 * vv;
w := x2 * x2;
w := c3 * w;
z := u + vv;
z := z + w;
FG_N1_unrank(q, v, 1, n, c);
minusz := -z;
if not IsOne(minusz) then
for i in [0..n-1] do
v[1 + 2 * i] := minusz * v[1 + 2 * i];
od;
fi;
return Permuted(v, perm);
end );
#############################################################################
#F QNumberElement( d, q, var ) returns the number of element <var> of Q(d,q)
# see QElementNumber for specification of form.
##
InstallGlobalFunction( QNumberElement,
function(d, q, var)
local wittindex, x, a, b, v, i, cyc;
cyc := PermList( Concatenation([2..d+1], [1]));
v := Permuted(StructuralCopy(var!.obj), cyc^-1);
wittindex := d/2;
x := FG_nb_pts_Sbar(wittindex, q);
if IsZero(v[2 * wittindex + 1]) then
a := FG_Sbar_rank(q, v, 1, wittindex);
return a + 1;
fi;
a := x;
if not IsOne(v[1 + 2 * wittindex]) then
PG_element_normalize(v, 1, d + 1);
fi;
if IsOddInt(q) then
for i in [0..d/2-1] do
v[2 * i+1] := -v[2 * i+1];
od;
fi;
b := FG_N1_rank(q, v, 1, wittindex);
return a + b + 1; ## adjustment for lists beginning at 1
end );
#############################################################################
#F QplusNumberElement( d, q, var ) returns the number of element <var> of Q+(d,q)
# see QplusNumberElement for specification of form.
##
InstallGlobalFunction( QplusNumberElement,
function(d, q, var)
local wittindex, a, v;
v := StructuralCopy(var!.obj);
wittindex := (d+1)/2;
a := FG_Sbar_rank(q, v, 1, wittindex);
return a + 1; ## adjustment for lists beginning at 1
end );
## still need to fix QminusNumberElement. Fixing means optimizing. It is tested and works beautifully. jdb. 30/9
#############################################################################
#F QminusNumberElement( d, q, var ) returns the number of element <var> of Q-(d,q)
# see QminusNumberElement for specification of form.
##
InstallGlobalFunction( QminusNumberElement,
function(d, q, var)
local wittindex, a, v, x, x1, x2, c1, c2, c3, perm,
form, i, u, w, vv, z, minusz, minuszv, c, b;
# Choose [c1, c2, c3] compatible with FinInG:
if IsEvenInt(q) then
form := QuadraticForm( EllipticQuadric(d, q) )!.matrix;
else
form := SesquilinearForm( EllipticQuadric(d, q) )!.matrix;
fi;
c1 := form[1][1];
c2 := form[1][2];
c3 := form[2][2];
wittindex := (d-1)/2;
perm := (1,d)(2,d+1); ## it would be nice to remove this permutation
v := StructuralCopy(var!.obj);
v := Permuted(v, perm);
PG_element_normalize(v, 1, d + 1);
x1 := v[1 + 2 * wittindex];
x2 := v[2 + 2 * wittindex];
if IsZero( x1 ) and IsZero( x2 ) then
a := FG_Sbar_rank(q, v, 1, wittindex);
return a + 1; ## adjustment for lists beginning at 1
fi;
a := FG_nb_pts_Sbar(wittindex, q);
if IsOne( x1 ) and IsZero( x2 ) then
b := 0;
else
if not IsOne( x2 ) then
Error("ERROR in Qminus_rank x2 <> 1");
fi;
b := FG_pos(q, x1) + 1;
fi;
x := FG_nb_pts_N1(wittindex, q);
u := c1 * x1 * x1;
vv := c2 * x1 * x2;
w := c3 * x2 * x2;
z := u + vv;
z := z + w;
if IsZero(z) then
Error("ERROR Qminus_rank z = 0");
fi;
minusz := -z;
minuszv := minusz^-1;
# JB (19/08/2014): Found the bug and it was that only the odd places need to be multiplied
if not IsOne( minusz ) then
for i in [0..wittindex-1] do
v[1 + 2 * i] := minuszv * v[1 + 2 * i];
od;
#v := minuszv * v;
fi;
c := FG_N1_rank(q, v, 1, wittindex);
return a + b * x + c + 1; ## adjustment for lists beginning at 1
end );
#############################################################################
## New hermitian stuff... These functions look quite interesting, but are never used...
#InstallGlobalFunction( enum_line,
# function( A, B, n )
## This function returns the n-th point on the interval
## ]A,B[. This routine uses the ordering of a finite field GF(q).
## For instance, we know that 0 and 1 are the first two elements of GF(q).
## The integer n must be between 1 and q - 1.
# local pg, q, x, C;
# pg := A!.geo;
# q := Size( pg!.basefield );
# x := FG_ffenumber( q, n + 1 ); ## n = 1 -> primitive root
# C := VectorSpaceToElement( pg, A!.obj + x * B!.obj );
# return C;
# end );
#InstallGlobalFunction( enum_BaerSubline,
# function( q, n )
## This function returns the n-th point on the canonical Baer subline
## X0^(q+1) + X1^(q+1), of PG(1, q^2).
## Note: Z(q^2)^(q+1) = Z(q) in GAP.
# local k, x;
## Our points are (1, Z(q^2)^i) such that Z(q)^i=-1 (i in [1..q^2-1]).
## This condition holds iff i = j (q-1) + k with j in [0..q],
## k = (q-1)/2 for q odd, k = q-1 for q even.
# if IsEvenInt(q) then
# k := q - 1;
# else
# k := (q - 1)/2;
# fi;
# x := [ Z(q)^0, Z(q^2)^( (n-1) * (q-1) + k ) ];
# return x;
# end );
#InstallGlobalFunction( enum_unital,
# function( q, n )
## This function returns the n-th point on the canonical unital
## X0^(q+1) + X1^(q+1) + X2^(q+1).
##
## First we use the representation of the classical unital U_{0,beta}
## from page 70 of Barwick and Ebert's book "Unitals in Projective Planes".
## That is:
## U_{0,beta} = {(x, beta * x^{q+1} + r, 1) : x in GF(q^2), r in GF(q)}\cup {(0,1,0)}.
## This representation has the advantage that it is simple to enumerate by
## elements of GF(q^2) x GF(q) (plus one extra point (0,1,0)).
## The Gram matrix for this Hermitian curve is
## [[beta-beta^q,0,0],[0,0,-1],[0,1,0]] * e where e^q+e=0.
##
# local beta, one, i, j, x, r, point, e, mat, b, binv;
# beta := Z(q^2);
# one := beta^0;
# if n = q^3 + 1 then
# point := [0,1,0] * one;
# else
# i := (n-1) mod q^2; ## an integer in [0..q^2-1]
# j := (n-1-((n-1) mod q^2)) / q^2; ## an integer in [0..q-1]
# x := FG_ffenumber( q^2, i );
# r := FG_ffenumber( q, j );
# point := [x, beta * x^(q+1)+ r, one];
# fi;
# if IsEvenInt(q) then
# e := Z(q^2)^(q+1);
# else
# e := Z(q^2)^((q+1)/2);
# fi;
# mat := [[beta-beta^q,0,0],[0,0,-1],[0,1,0]] * e;
# b := BaseChangeToCanonical( HermitianFormByMatrix(mat, GF(q^2)) );
# binv := b^-1;
# return point * binv;
# end );
#############################################################################
#############################################################################
#F HermElementNumber( d, q, a ) returns element number a of H(d,q^2). see
# below for form.
##
InstallGlobalFunction( HermElementNumber,
function(d, q, a)
# The hermitian form here is simply
# x(1) x(2)^q + ... + x(n-1) x(n)^q
local n, v, i, a2;
#zero := 0*Z(q);
a2 := a - 1;
v := ListWithIdenticalEntries(d+1,Z(q)^0);
n := Int((d+1) / 2);
FG_herm_Sbar_unrank(Sqrt(q),v,1,d+1,a2);
return v;
end );
#############################################################################
#F HermElementNumber( d, q, var ) returns the number of the element <var>
# of H(d,q^2), see HermElementNumber for the form.
##
InstallGlobalFunction( HermNumberElement,
function(d, q, var)
local wittindex, a, v,y;
v := StructuralCopy(var!.obj);
y := v[PositionNonZeroFromRight(v)];
if IsOddInt(q) then
y := y/(Z(q)^((Sqrt(q)-1)/2)); #Strange Anton normalization...
fi;
v := v/y;
#wittindex := (d+1)/2;
a := FG_herm_Sbar_rank(Sqrt(q), v, 1, d+1);
return a + 1; ## adjustment for lists beginning at 1
end );
#############################################################################
# The enumerator for points of a polar space, bundled in one operation.
#############################################################################
InstallMethod( AntonEnumerator,
"for a collection of subspaces of a polar space",
[IsSubspacesOfClassicalPolarSpace],
## This operation puts together the Anton's code into
## an organised form. It computes an enumerator just
## for points of a polar space. Thereafter, for higher variety
## types, induction by non-degenerate hyperplane sections is
## used (except for symplectic spaces).
function( vs )
local ps, enum, flavour, d, q, projenum;
if vs!.type <> 1 then
Error("Only applicable to points");
fi;
ps := vs!.geometry;
flavour := PolarSpaceType(ps);
d := ps!.dimension;
q := Size(ps!.basefield);
if flavour = "parabolic" then
## Parabolic
enum := EnumeratorByFunctions( vs, rec(
ElementNumber := function( e, n )
return VectorSpaceToElement(ps, QElementNumber(d, q, n));
end,
NumberElement := function( e, x )
return QNumberElement(d, q, x);
end )
);
elif flavour = "hyperbolic" then
## Hyperbolic
enum := EnumeratorByFunctions( vs, rec(
ElementNumber := function( e, n )
return VectorSpaceToElement(ps, QplusElementNumber(d, q, n));
end,
NumberElement := function( e, x )
return QplusNumberElement(d, q, x);
end )
);
elif flavour = "elliptic" then
## Elliptic
enum := EnumeratorByFunctions( vs, rec(
ElementNumber := function( e, n )
return VectorSpaceToElement(ps, QminusElementNumber(d, q, n));
end,
NumberElement := function( e, x )
return QminusNumberElement(d, q, x);
end )
);
elif flavour = "symplectic" then
## Symplectic (uses just the enumerator for the points of
## the ambient projective space)
projenum := Enumerator( Points(AmbientSpace(ps)) );
enum := EnumeratorByFunctions( vs, rec(
ElementNumber := function( e, n )
return VectorSpaceToElement(ps, projenum[n]!.obj);
end,
NumberElement := function( e, x )
return Position(projenum, x);
end )
);
elif flavour = "hermitian" then
## Hermitian
enum := EnumeratorByFunctions( vs, rec(
ElementNumber := function( e, n )
return VectorSpaceToElement(ps, HermElementNumber(d, q, n));
end,
NumberElement := function( e, x )
return HermNumberElement(d, q, x);
end )
);
# projenum := EnumeratorByOrbit( Points( ps ) ); ## this computes the whole list of points!!
# enum := EnumeratorByFunctions( vs, rec(
# ElementNumber := function( e, n )
# return VectorSpaceToElement(ps, projenum[n]!.obj);
# end,
# NumberElement := function( e, x )
# return Position(projenum, x);
# end )
# );
else
Error("not implemented for this polar space");
fi;
return enum;
end );
#############################################################################
# Low level enumerators
#############################################################################
#############################################################################
#F FG_specialresidual: our special helper enumerator function that returns
# an enumerator (actually just a list) of elements of dimension j on a given j-1
# space, not in a given hyperplane.
##
InstallGlobalFunction(FG_specialresidual,
function(ps, v, hyp)
## This function returns an enumerator for the j spaces on a
## given j-1 space v which are not contained in a hyperplane hyp.
## This could be made more efficient.
local j, enum, res;
j := v!.type + 1;
res := Enumerator( ShadowOfElement(ps, v, j) );
enum := Filtered(res, x -> not x in hyp);
return enum;
end );
#############################################################################
#F FG_enum_orthogonal. This is a "helper" function which makes the enumerator
# for a set of elements of a canonical orthogonal space.
##
InstallGlobalFunction( FG_enum_orthogonal,
function( ps, j )
local hyp, pg, d, f, iter, x, ps2, vs, ressize,
em, varsps2jmin1, varsps2j, enum2, enum, enumextra,
vars, rep, disc, sqs, type, q, zero, one;
vs := ElementsOfIncidenceStructure(ps, j);
if j = 1 then
enum := AntonEnumerator( vs );
elif j > 1 then
pg := AmbientSpace(ps);
type := PolarSpaceType(ps);
d := ps!.dimension;
f := ps!.basefield;
q := Size(f);
zero := Zero(f);
one := One(f);
## The number of j spaces on a j-1 space is the number of points
## in the quotient polar space (over a j-1 space)
x := List([1..d], i -> zero);
hyp := ShallowCopy(IdentityMat(d,f));
if type = "parabolic" or type = "elliptic" then
hyp := Concatenation([x], hyp);
else
x[2] := one;
x[d] := one;
Append(hyp, [x]);
fi;
hyp := TransposedMat(hyp);
hyp := VectorSpaceToElement(pg, hyp);
disc := TypeOfSubspace(ps, hyp);
## Here ps2 is the polar space induced by the hyperplane section.
## ressize is the number of j spaces not contained in hyp
## incident with a j-1 space contained in hyp. Of course, we
## have a special case when j is the Witt index.
if type = "hyperbolic" then
ps2 := ParabolicQuadric(d-1, f);
ressize := Size(ElementsOfIncidenceStructure(HyperbolicQuadric(d+2-2*j, f), 1));
#if j <= WittIndex( SesquilinearForm(ps2) ) then
if j <= WittIndex( QuadraticForm(ps2) ) then #was "SesquilinearForm"
ressize := ressize - Size(ElementsOfIncidenceStructure(ParabolicQuadric(d+1-2*j, f), 1));
fi;
elif type = "elliptic" then
ps2 := ParabolicQuadric(d-1, f);
ressize := Size(ElementsOfIncidenceStructure(EllipticQuadric(d+2-2*j, f), 1));
#if j <= WittIndex( SesquilinearForm(ps2) ) then
if j <= WittIndex( QuadraticForm(ps2) ) then #was "SesquilinearForm"
ressize := ressize - Size(ElementsOfIncidenceStructure(ParabolicQuadric(d+1-2*j, f), 1));
fi;
# type = "parabolic" in what follows
elif disc = "elliptic" then
ps2 := EllipticQuadric(d-1, f);
ressize := Size(ElementsOfIncidenceStructure(ParabolicQuadric(d+2-2*j, f), 1));
#if j <= WittIndex( SesquilinearForm(ps2) ) then
if j <= WittIndex( QuadraticForm(ps2) ) then #was "SesquilinearForm"
ressize := ressize - Size(ElementsOfIncidenceStructure(EllipticQuadric(d+1-2*j, f), 1));
fi;
else
ps2 := HyperbolicQuadric(d-1, f);
ressize := Size(ElementsOfIncidenceStructure(ParabolicQuadric(d+2-2*j, f), 1));
#if j <= WittIndex( SesquilinearForm(ps2) ) then
if j <= WittIndex( QuadraticForm(ps2) ) then #was "SesquilinearForm"
ressize := ressize - Size(ElementsOfIncidenceStructure(HyperbolicQuadric(d+1-2*j, f), 1));
fi;
fi;
em := NaturalEmbeddingBySubspace(ps2, ps, hyp);
## Enumerate last the j-spaces contained in the non-deg hyperplane
#if j <= WittIndex( SesquilinearForm(ps2) ) then
if j <= WittIndex( QuadraticForm(ps2) ) then #was SesquilinearForm
varsps2j := ElementsOfIncidenceStructure( ps2, j );
enumextra := Enumerator( varsps2j );
fi;
varsps2jmin1 := ElementsOfIncidenceStructure( ps2, j-1 );
enum2 := FG_enum_orthogonal( ps2, j-1);
enum := EnumeratorByFunctions( vs, rec(
ElementNumber := function( e, n )
local l, k, enumres, t, v;
if n > Size(enum2) * ressize then
l := n - Size(enum2) * ressize;
return enumextra[l]^em;
else
## The way this works is that n is the position
## of the l-th j-space incident with the k-th (j-1)-space
## of vars2ps2. So we must first decompose n as n=(k-1)ressize+l.
l := RemInt(n, ressize);
if l = 0 then l := ressize; fi;
k := (n-l) / ressize + 1;
v := enum2[k]^em;
enumres := FG_specialresidual(vs!.geometry, v, hyp);
return enumres[l];
fi;
end,
NumberElement := function( e, x )
## Here we must first find the unique j-1 space
## incident with x, and then find its place in the ordering.
local w, prew, k, enumres, l, numinhyp;
## first deal with the case that x is in hyp
if x in hyp then
numinhyp := Size(enum2) * ressize;
prew := em!.prefun(x);
return numinhyp + Position(enumextra, prew);
else
w := Meet(hyp, x);
prew := em!.prefun(w);
k := Position(enum2, prew);
enumres := FG_specialresidual(vs!.geometry, w, hyp);
l := Position(enumres, x);
return (k-1)*ressize + l;
fi;
end ) );
else
Error("j must be a positive integer");
fi;
return enum;
end );
#############################################################################
#F FG_enum_hermitian. This is a "helper" function which makes the enumerator
# for a set of elements of a canonical hermitian space.
# bug repaired in NumberElement function. Bug found by Frédéric Vanhove.
##
InstallGlobalFunction( FG_enum_hermitian,
function( ps, j )
local hyp, pg, d, f, ps2, vs, ressize, em, varsps2jmin1,
varsps2j, enum2, enum, enumextra, vars;
vs := ElementsOfIncidenceStructure(ps, j);
if j = 1 then
enum := AntonEnumerator( vs );
elif j > 1 then
pg := AmbientSpace(ps);
d := ps!.dimension;
f := ps!.basefield;
hyp := NullMat(d,d+1,f);
hyp{[1..d]}{[2..d+1]} := IdentityMat(d, f);
hyp := VectorSpaceToElement(pg, hyp);
## ps2 is the polar space induced by the hyperplane section.
## ressize is the number of j spaces not contained in hyp
## incident with a j-1 space contained in hyp.
ps2 := HermitianPolarSpace(d-1, f);
ressize := Size(ElementsOfIncidenceStructure(HermitianPolarSpace(d+2-2*j, f), 1));
if j <= WittIndex( SesquilinearForm(ps2) ) then
ressize := ressize - Size(ElementsOfIncidenceStructure(HermitianPolarSpace(d+1-2*j, f), 1));
varsps2j := ElementsOfIncidenceStructure( ps2, j );
enumextra := Enumerator( varsps2j );
fi;
em := NaturalEmbeddingBySubspace(ps2, ps, hyp);
varsps2jmin1 := ElementsOfIncidenceStructure( ps2, j-1 );
enum2 := FG_enum_hermitian( ps2, j-1 );
enum := EnumeratorByFunctions( vs, rec(
ElementNumber := function( e, n )
local l, k, enumres, t, v;
if n > Size(enum2) * ressize then
l := n - Size(enum2) * ressize;
return enumextra[l]^em;
else
l := RemInt(n, ressize);
if l = 0 then l := ressize; fi;
k := (n-l) / ressize + 1;
v := enum2[k]^em;
enumres := FG_specialresidual(vs!.geometry, v, hyp);
return enumres[l];
fi;
end,
NumberElement := function( e, x )
local w, prew, k, enumres, l, numinhyp;
if x in hyp then
numinhyp := Size(enum2) * ressize;
#prew := PreImage(em, x); #this was bug 1
prew := em!.prefun(x);
return numinhyp + Position(enumextra, prew);
else
w := Meet(hyp, x);
#prew := PreImage(em, w); #this was bug 2
prew := em!.prefun(w);
#k := Position(varsps2jmin1, prew); this was bug 3
k := Position(enum2, prew);
enumres := FG_specialresidual(vs!.geometry, w, hyp);
l := Position(enumres, x);
return (k-1)*ressize + l;
fi;
end ) );
else
Error("j must be a positive integer");
fi;
return enum;
end );
#############################################################################
#F FG_enum_symplectic.
##
InstallGlobalFunction( FG_enum_symplectic,
## This is a "helper" function which makes the enumerator
## for a set of varieties of a symplectic space. We would
## like an algorithm for these. Recall that for the orthogonal
## and hermitian cases, we used induction by non-degenerate
## hyperplane sections to calculate the enumerators. We do not
## have non-degenerate hyperplanes in symplectic spaces!
function( ps, j )
local vs, vars, enum;
vs := ElementsOfIncidenceStructure(ps, j);
vars := EnumeratorByOrbit( vs );
enum := EnumeratorByFunctions( vs, rec(
ElementNumber := function( e, n )
return vars[n];
end,
NumberElement := function( e, x )
return Position(vars, x);
end ) );
return enum;
end );
#############################################################################
# Some left over
#############################################################################
#merge these two, give it a sensible name, see if one can be thrown away... done.
#InstallGlobalFunction(my_PG_element_normalize,
# [IsFFECollection, IsPosInt, IsPosInt],
# function(v, offset, n)
## This function takes the first nonzero element
## from the right (!) and normalises the vector v
## by this element.
# local ii, i, a, one;
# one := One(v[1]);
# for ii in [0..n - 1] do
# i := n - 1 - ii;
# a := v[offset + i];
# if not IsZero(a) then
# if IsOne(a) then
# return;
# fi;
# a := a^-1;
# v{[offset..i-1+offset]} := a * v{[offset..i-1+offset]};
# v[offset + i] := one;
# return;
# fi;
# od;
# Error("zero vector");
#
#end );
#############################################################################
# The enumerator using the orbit. This is the only operation declaration in
# this file for a user intended operation.
#############################################################################
#############################################################################
#O EnumeratorByOrbit. returns an enumerator using the orbit.
##
InstallMethod( EnumeratorByOrbit,
"for a collection of subspaces of a polar space",
[ IsSubspacesOfClassicalPolarSpace ],
function( vs )
## In this operation, we provide a way to compute the full
## list of elements by using the transitive action of the isometry
## group. Using an enumerator to get a full list is much slower.
## We use the package "orb" by Mueller, Neunhoeffer and Noeske,
## which is much quicker than using the standard orbit algorithm
## that exists in GAP.
local ps, j, rep, vars, isom, gens;
ps := vs!.geometry;
j := vs!.type;
isom := IsometryGroup(ps);
gens := GeneratorsOfGroup(isom);
rep := RepresentativesOfElements(ps)[j];
vars := Orb(gens,rep,OnProjSubspaces, rec( hashlen:=Int(5/4*Size(vs)) ));
Enumerate(vars, Size(vs));
return vars;
end );
# jdb: patched 15/2/2016, using a patch file from Max Horn.
#############################################################################
#O AsList. Lists all elements in a collection of subspaces of polar space.
##
InstallMethod( AsList,
"for subspaces of a polar space",
[IsSubspacesOfClassicalPolarSpace],
function( vs )
return AsList(EnumeratorByOrbit( vs ));
end );
# jdb: patched 15/2/2016, using a patch file from Max Horn.
#############################################################################
#O AsSortedList. Lists all elements in a collection of subspaces of polar space.
##
InstallMethod( AsSortedList,
"for subspaces of a polar space",
[IsSubspacesOfClassicalPolarSpace],
function( vs )
return AsSortedList(EnumeratorByOrbit( vs ));
end );
#Exactly the same as above?
#############################################################################
#O AsSortedList. Lists all elements in a collection of subspaces of polar space.
##
InstallMethod( AsSSortedList,
"for subspaces of a polar space",
[IsSubspacesOfClassicalPolarSpace],
function( vs )
return AsSortedList(EnumeratorByOrbit( vs ));
end );
#############################################################################
#O Enumerator.
# This is it! This is the big method that returns an enumerator for a collection
# of all elements of a given type of the polar space <ps>
##
InstallMethod( Enumerator,
"for subspaces of a polar space",
[ IsSubspacesOfClassicalPolarSpace ],
function( vs )
## This method returns the enumerator for the elements of
## a polar space, of a given type. There are three "helper"
## operations involved here: FG_enum_orthogonal, FG_enum_hermitian,
## and FG_enum_symplectic. At the moment, we do not have nice methods
## for the points of a hermitian space, and for varieties of
## a symplectic space.
local ps, j, rep, enum, e, type, eEN, eNE, iso, pscanonical;
ps := vs!.geometry;
j := vs!.type;
type := PolarSpaceType(ps);
## A bug here was fixed. When using non-canonical polar spaces, there was some problem
## in using the enum_* commands before an isomorphism was made. Fixed now. John 02/06/2010
if HasIsCanonicalPolarSpace( ps ) and IsCanonicalPolarSpace( ps ) then
if type in [ "hyperbolic", "elliptic", "parabolic" ] then
e := FG_enum_orthogonal(ps, j);
elif type = "hermitian" then
e := FG_enum_hermitian(ps, j);
elif type = "symplectic" then
e := FG_enum_symplectic(ps, j);
else
Error("Unknown polar space type");
fi;
enum := EnumeratorByFunctions( vs, rec(
ElementNumber := e!.ElementNumber,
NumberElement := e!.NumberElement,
PrintObj := function ( e )
Print( "EnumeratorOfSubspacesOfClassicalPolarSpace( " );
View( vs );
Print( " )" );
return;
end,
Length := function( e )
return Size(vs);
end
) );
else
## The following is an isomorphism from the canonical polar space TO ps
iso := IsomorphismCanonicalPolarSpace( ps );
pscanonical := Source(iso)!.geometry;
if type in [ "hyperbolic", "elliptic", "parabolic" ] then
e := FG_enum_orthogonal(pscanonical, j);
elif type = "hermitian" then
e := FG_enum_hermitian(pscanonical, j);
elif type = "symplectic" then
e := FG_enum_symplectic(pscanonical, j);
else
Error("Unknown polar space type");
fi;
## These are enumerators in the canonical polar spaces
eEN := e!.ElementNumber;
eNE := e!.NumberElement;
enum := EnumeratorByFunctions( vs, rec(
ElementNumber := function(e, n)
return iso!.fun( eEN( e, n ) );
end,
NumberElement := function(e, x)
return eNE( e, iso!.prefun(x) );
end,
--> --------------------
--> maximum size reached
--> --------------------
[ Verzeichnis aufwärts0.55unsichere Verbindung
Übersetzung europäischer Sprachen durch Browser
]
|