    /*
    ------------------------------------------------------------------------
    Efficient Galois Fields in Maxima

    by Alasdair McAndrew
    and later extended by Fabrizio Caruso and Jacopo Daurizio

    it is distribuited together with gf_roots by Jacopo Daurizio

    Authors:

    Fabrizio Caruso   (optimizations, testing)
    Jacopo D'Aurizio   (optimizations, modular roots)
    Alasdair McAndrew (original version of the package, pohlig-helman log, etc... )
    ------------------------------------------------------------------------*/

    /* Released under terms of the GNU General Public License, version 2,
     * by permission of the authors to Robert Dodier circa 2007-12-02.
     */

    /* Defines a flag for dealing with large fields.  If it is set to "false",
    then lookup tables are used for exponentiation and logarithms.  Otherwise
    other algorithms are used */

    define_variable(largefield,true,bool)$
    define_variable(gf_char,0,integer)$
    define_variable(gf_exp,0,integer)$
    define_variable(gf_order,0,integer)$
    define_variable (gf_one, 'gf_one, any_check)$
    define_variable (gf_prim, 'gf_prim, any_check)$
    define_variable (gf_irr, 'gf_irr, any_check)$
    define_variable (gf_list, 'gf_list, any_check)$
    define_variable (gen_powers, 'gf_list, any_check)$
    remvalue(x,z,gf_char,gf_exp,gf_irr,pg,gp,lg,gf_prim,gf_one,gf_order,gf_list,gen_powers)$

    /* --------------------------------------------------------------------------------------------- */
    /* Settings */

    GF_VERBOSE:false; /* Verbosity */
    GF_WARNING: true; /* Warnings */
    GF_IRREDUCIBILITY_CHECK:false;   /* Irreducibility test for the minimal polynomial of the extension */

    /*
    ------------------------------------------------------------------------------------------------ */

    /* It defines a new current field with gf_char=b, min. pol.= p of deg= e*/
    gf_set([ars]):=block([gj,m,i,j,dg],
      if length(ars)=1 then
        (
        gf_setp(ars[1]),
        return(true)
        )
      else
        (
        if length(ars)=2 then
           (
           if numberp(ars[2]) then
             (
             if ars[2]=0 and GF_WARNING then
               (
               print("WARNING: the irreducible is zero! We assume GF(",ars[1],")"),
               gf_setp(ars[1]),
               return(true)
               )
             else
               (
               error("ERROR: you tried to extend with a non-zero constant!"),
               return(false)
               )
             )
           else
             (
             dg:hipow(ars[2],x),

             if dg=1 then
               gf_setp(ars[1]),
             gf_irr:ars[2],
             gf_exp:dg,
             return(true)
             )
           )
        else
           (
           gf_exp:ars[2],
           if gf_exp=1 then
              (
              gf_setp(ars[1]),
              gf_irr:rat(ars[3]),
              return(true)
              ),
           gf_irr:rat(ars[3])
           )
        ),

      gf_char:ars[1],
      gf_one:rat(1,x),
      gf_order:gf_char^gf_exp-1,

      m:makelist(coeff(gf_irr,x,i),i,0,gf_exp),
      gf_list:[[first(m),0]],j:1,
      for i:2 thru gf_exp+1 do if m[i]=0 then j:j+1 else ( gf_list:endcons([m[i],j],gf_list), j:1 ),

      if not(primep(gf_char)) then error("ERROR: Gf_Char must be a prime number.")
        else
          modulus:gf_char,
      if GF_IRREDUCIBILITY_CHECK and
           hipow(args(factor(ars[3]))[1],x)#hipow(rat(ars[3]),x) then
          error("ERROR: Polynomial is not irreducible"),

      if not(largefield) then
         (
         pg:mkpowers(),
         lg:mklogs()
         )
      else
         (
         if GF_VERBOSE then
           print("finding a primitive element..."),

         gf_prim:rat(gf_findprim(),x),
         if GF_VERBOSE then
         print("...primitive element found.")

         ),
      modulus:false, /* it resets the modulus */
      return(true)

      )$

    /* Prints out information about the field */
    gf_info():=block(
      print("Prime gf_char value: ",gf_char),
      print("Exponent: ", gf_exp),
      print("Multiplicative order: ",gf_order),
      print("Irreducible polynomial: ",gf_irr),
      print("Primitive element: ",gf_prim),
      if (largefield) then
        print("Largefield flag is true; powers and logarithms not computed.")
        else
        print("Largefield flag is false; powers and logarithms computed."),
      disp()
    )$