function rel(a, m, r)
  k := Parent(a);   // GF(p)
  p := Characteristic(k);
  return (1 + a^(p-m) - (k!2)^(p-m))*
         (1 - (k!2)^(p+m-r))*(1 - (a-1)^(p+m-r));
end function;


function reltab(p, r)
  assert Type(p) eq RngIntElt and IsPrime(p) and IsOdd(p);
  assert Type(r) eq RngIntElt and IsEven(r);

  nr := (p-3) div 2; 
  nc := (p-1) div 2;
  M  := RMatrixSpace(GF(p),nr,nc)!0;
  t := Cputime();
  for i in [1..nr] do
     print Cputime(t),":   ",i, "\t",i/nr*1.0;
     for j in [1..nc] do
        a := GF(p)!(2*(i+1));
        M[i, j] := rel(a, 2*j-1, r);
     end for;
  end for;
  return M;
end function;

function antientry(p, r, x, y)
  if ((x-y) mod (p-1) eq 0) or ((x+y-r) mod (p-1) eq 0) then
     return 1;
  else
     return 0;
  end if;
end function;

function antitab(p, r)
  assert Type(p) eq RngIntElt and IsPrime(p) and IsOdd(p);
  assert Type(r) eq RngIntElt and IsEven(r);

  nr := 1 + Floor((p-1)/4); 
  nc := (p-1) div 2;
  c  := (r div 2) - ((r div 2) mod 2);

  M  := RMatrixSpace(GF(p),nr,nc)!0;
  for i in [1..nr] do
     for j in [1..nc] do
        M[i, j] := antientry(p, r, 2*i+c-1, 2*j-1);
     end for;
  end for;
  return M;
end function;

function wholetab(p, r)
  "Making reltab...";
  time Mrel := reltab(p,r);
  "Making antitab...";
  time Manti := antitab(p,r);
  M := RMatrixSpace(GF(p),Nrows(Mrel)+Nrows(Manti),Ncols(Mrel))!0;
  for r in [1..Nrows(Mrel)] do
     M[r] := Mrel[r];
  end for;
  for r in [1..Nrows(Manti)] do
     M[r+Nrows(Mrel)] := Manti[r];
  end for;
  return M;
end function;

function kerp(p,r)
   print "Building matrix...";
   time M := wholetab(p,r);
   print "Computing kernel...";
   time V := Kernel(Transpose(M));
   return V;
end function;













