ALPHABET := {@ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L",
     "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" @};

function ToCode(n)
   // Returns the n-th letter coding.  The coding goes A,B,C,...,Z,AA,BB,...
   if n eq 0 then return "?"; end if;
   return &cat[ALPHABET[((n-1)mod 26)+1]: i in [0..((n-1) div 26)]];
end function;


function HasseArthur(p, n)
   assert Type(p) eq RngIntElt;
   assert Type(n) eq RngIntElt;
   assert IsPrime(p);
   assert n ge 1;

   F := GaloisField(p);

   S := PolynomialRing(F,n+1);
   names := [ToCode(i) : i in [1..n+1]];
   names[#names] := "t";
   AssignNames(~S, names);
   

   t := S.(n+1);

   Q, pi := quo<S | [S.i^p : i in [1..n]]>;
 
   tt := pi(t);

   U := &+[pi(S.i)^n : i in [1..n]] + tt * &*[pi(S.i) : i in [1..n]]; 

   "U = ", U;
   
   return U^(p-1);

end function;

