)abbrev domain FFCGP FiniteFieldCyclicGroupExtensionByPolynomial
++ Authors: J.Grabmeier, A.Scheerhorn
++ Date Created: 26.03.1991
++ Basic Operations:
++ Related Constructors: FiniteFieldFunctions
++ Also See: FiniteFieldExtensionByPolynomial,
++  FiniteFieldNormalBasisExtensionByPolynomial
++ AMS Classifications:
++ Keywords: finite field, primitive elements, cyclic group
++ References:
++  R.Lidl, H.Niederreiter: Finite Field, Encycoldia of Mathematics and
++  Its Applications, Vol. 20, Cambridge Univ. Press, 1983, ISBN 0 521 30240 4
++  J. Grabmeier, A. Scheerhorn: Finite Fields in AXIOM.
++  AXIOM Technical Report Series, ATR/5 NP2522.
++ Description:
++  FiniteFieldCyclicGroupExtensionByPolynomial(GF, defpol)  implements a
++  finite extension field of the ground field {\em GF}. Its elements are
++  represented by powers of a primitive element, i.e. a generator of the
++  multiplicative (cyclic) group. As primitive
++  element we choose the root of the extension polynomial {\em defpol},
++  which MUST be primitive (user responsibility). Zech logarithms are stored
++  in a table of size half of the field size, and use \spadtype{SingleInteger}
++  for representing field elements, hence, there are restrictions
++  on the size of the field.


FiniteFieldCyclicGroupExtensionByPolynomial(GF, defpol) : _
  Exports == Implementation where
  GF    : FiniteFieldCategory                -- the ground field
  defpol : SparseUnivariatePolynomial GF      -- the extension polynomial
  -- the root of defpol is used as the primitive element

  PI    ==> PositiveInteger
  NNI   ==> NonNegativeInteger
  I     ==> Integer
  SI    ==> SingleInteger
  SUP   ==> SparseUnivariatePolynomial
  SAE   ==> SimpleAlgebraicExtension(GF, SUP GF, defpol)
  V     ==> Vector GF
  FFP   ==> FiniteFieldExtensionByPolynomial(GF, defpol)
  FFF   ==> FiniteFieldFunctions(GF)
  OUT   ==> OutputForm
  ARR   ==> PrimitiveArray(SI)
  TBL   ==> Table(PI, NNI)


  Exports ==> FiniteAlgebraicExtensionField(GF)  with

    getZechTable : () -> ARR
      ++ getZechTable() returns the zech logarithm table of the field
      ++ it is used to perform additions in the field quickly.
  Implementation ==>  add

-- global variables ===================================================

    Rep := SI
    -- elements are represented by small integers in the range
    -- (-1)..(size()-2). The (-1) representing the field element zero,
    -- the other small integers representing the corresponding power
    -- of the primitive element, the root of the defining polynomial

    -- it would be very nice if we could use the representation
    -- Rep := Union("zero", IntegerMod(size()$GF ^ degree(defpol) -1)),
    -- why doesn't the compiler like this ?

    qzero ==> (-1)@SI

    extdeg : NNI  := degree(defpol)$(SUP GF)::NNI
    -- the extension degree

    sizeFF : NNI := qcoerce(size()$GF ^ extdeg)
    -- the size of the field

    if sizeFF > 2^20 then
      error "field too large for this representation"

    sizeCG : SI := qconvert(sizeFF - 1)
    -- the order of the cyclic group

    sizeFG : SI := qconvert(sizeCG quo (size()$GF - 1))
    -- the order of the factor group


    zechlog : ARR := new(((sizeFF+1) quo 2)::NNI, -1::SI)$ARR
    -- the table for the zech logarithm

    alpha := new()$Symbol :: OutputForm
    -- get a new symbol for the output representation of
    -- the elements

    primEltGF : GF :=
      odd?(extdeg)$I => -$GF coefficient(defpol, 0)$(SUP GF)
      coefficient(defpol, 0)$(SUP GF)
    -- the corresponding primitive element of the ground field
    -- equals the trace of the primitive element w.r.t. the ground field

    facOfGroupSize := []$(List Record(factor : Integer, exponent : NNI))
    -- the factorization of sizeCG

    initzech? : Boolean := true
    -- gets false after initialization of the zech logarithm array

    initelt? : Boolean := true
    -- gets false after initialization of the normal element

    normalElt : SI := 0
    -- the global variable containing a normal element

-- functions ==========================================================

    -- for completeness we have to give a dummy implementation for
    -- 'tableForDiscreteLogarithm', although this function is not
    -- necessary in the cyclic group representation case

    tableForDiscreteLogarithm(fac) == table()$TBL


    getZechTable() == zechlog
    initializeZech : () -> Void
    initializeElt : () -> Void

    order(x : %) : PI ==
      zero?(x) =>
        error"order: order of zero undefined"
      (sizeCG quo gcd(sizeCG, qcoerce(convert(x)@I)@NNI))::PI

    primitive?(x : %) ==
      zero?(x) or (x = 1) => false
      gcd(x::Rep, sizeCG)$Rep = 1$Rep => true
      false

    coordinates(x : %) ==
      x = 0 => new(extdeg, 0)$(Vector GF)
      primElement : SAE := convert(monomial(1, 1)$(SUP GF))$SAE
-- the primitive element in the corresponding algebraic extension
      coordinates(primElement ^$SAE convert(x)@I)$SAE

    x : % + y : % ==
      if initzech? then initializeZech()
      x =$Rep qzero => y
      y =$Rep qzero => x
      d : Rep := submod(y, x, sizeCG)$Rep
      d <= shift(sizeCG, -$SI (1$SI)) =>
        zechlog.(convert(d)@I) =$SI -1::SI => qzero
        addmod(x, zechlog.(convert(d)@I), sizeCG)$Rep
      --d: Rep := positiveRemainder(x -$Rep y, sizeCG)$Rep
      d : Rep := (sizeCG -$SI d)::Rep
      addmod(y, zechlog.(convert(d)@I), sizeCG)$Rep
      --positiveRemainder(x +$Rep zechlog.(convert(d)@I) -$Rep d, sizeCG)$Rep


    initializeZech() ==
      zechlog := createZechTable(defpol)$FFF
      -- set initialization flag
      initzech? := false
      void()$Void

    basis(n : PI) ==
      extensionDegree() rem n ~= 0 =>
        error("argument must divide extension degree")
      m := sizeCG quo (size()$GF^n-1)
      [index((1+i*m) ::PI) for i in 0..(n-1)]::Vector %

    n : I * x : % == ((n::GF)::%) * x

    minimalPolynomial(a) ==
      f : SUP % := monomial(1, 1)$(SUP %) - monomial(a, 0)$(SUP %)
      u : % := Frobenius(a)
      while not(u = a) repeat
        f := f * (monomial(1, 1)$(SUP %) - monomial(u, 0)$(SUP %))
        u := Frobenius(u)
      p : SUP GF := 0$(SUP GF)
      while not zero?(f)$(SUP %) repeat
        g : GF := retract(leadingCoefficient(f)$(SUP %))
        p := p+monomial(g, _
                      degree(f)$(SUP %))$(SUP GF)
        f := reductum(f)$(SUP %)
      p

    factorsOfCyclicGroupSize() ==
      if empty? facOfGroupSize then initializeElt()
      facOfGroupSize

    representationType() == "cyclic"

    definingPolynomial() == defpol

    random() == random(qconvert(sizeFF))$Rep -$Rep 1$Rep



    represents(v) ==
      u : FFP := represents(v)$FFP
      u =$FFP 0$FFP => 0
      qconvert(discreteLog(u)$FFP)



    coerce(e : GF) : % ==
      zero?(e)$GF => 0
      log : I := discreteLog(primEltGF, e)$GF::NNI *$I sizeFG
      -- version before 10.20.92: log pretend Rep
      -- 1$GF is coerced to sizeCG pretend Rep by old version
      -- now 1$GF is coerced to 0$Rep which is correct.
      qconvert(positiveRemainder(log, sizeCG))


    retractIfCan(x : %) ==
      zero? x => 0$GF
      u := (x::Rep) exquo$Rep qconvert(sizeFG)
      u = "failed" => "failed"
      primEltGF ^$GF (convert(u::%)@I)

    retract(x : %) ==
      a := retractIfCan(x)
      a="failed" => error "element not in ground field"
      a :: GF

    basis() == [index(i :: PI) for i in 1..extdeg]::Vector %


    inGroundField?(x) ==
      zero? x=> true
      positiveRemainder(x::Rep, qconvert(sizeFG))$Rep =$Rep 0$Rep => true
      false

    discreteLog(b : %, x : %) ==
      zero? x => "failed"
      e := extendedEuclidean(b, sizeCG, x)$Rep
      e = "failed" => "failed"
      e1 : Record(coef1 : %, coef2 : %) := e :: Record(coef1 : %, coef2 : %)
      qcoerce(convert(positiveRemainder(e1.coef1, sizeCG)$Rep)@I)

    - x : % ==
        x =$Rep qzero => qzero
        characteristic() =$I 2 => x
        addmod(x, shift(sizeCG, -1)$SI, sizeCG)

    generator() == 1$SI
    createPrimitiveElement() == 1$SI
    primitiveElement() == 1$SI

    discreteLog(x : %) ==
      zero? x => error "discrete logarithm error"
      qcoerce(convert(x)@I)

    normalElement() ==
      if initelt? then initializeElt()
      normalElt::%

    initializeElt() ==
      facOfGroupSize := factors(factor(sizeCG)$Integer)
      normalElt := createNormalElement()::Rep
      initelt? := false
      void()$Void

    extensionDegree() : PI == qcoerce(extdeg)

    characteristic() == characteristic()$GF

    lookup(x : %) ==
      x =$Rep (-$Rep 1$Rep) => qcoerce(sizeFF)
      qcoerce(convert(x +$Rep 1$Rep)@I)

    index(a : PI) ==
      qconvert(positiveRemainder(a, sizeFF)$I) -$Rep 1$Rep

    0 == (-$Rep 1$Rep)

    1 == 0$Rep

-- to get a "exponent like" output form
    coerce(x : %) : OUT ==
        x =$Rep (-$Rep 1$Rep) => message("0")
        x =$Rep 0$Rep => message("1")
        y : I := lookup(x) - 1
        alpha ^$OUT (y::OUT)

    x : % = y : % ==  x =$Rep y

    x : % * y : % ==
      x =$Rep qzero => qzero
      y =$Rep qzero => qzero
      addmod(x, y, sizeCG)$Rep

    a : GF * x : % == coerce(a)@% * x
    x : %/a : GF == x/coerce(a)@%

--    x: % / a: GF ==
--      a = 0$GF => error "division by zero"
--      x * inv(coerce(a))

    inv(x : %)  ==
      zero?(x) => error "inv: not invertible"
      (x = 1) => 1
      sizeCG -$Rep x

    x : % ^ n : PI == x ^ n::I

    x : % ^ n : NNI == x ^ n::I

    x : % ^ n : I ==
      m : Rep := qconvert(positiveRemainder(n, sizeCG)$I)
      m =$Rep 0$Rep => 1
      x = 0 => 0
      mulmod(m, x, sizeCG::Rep)$Rep

)abbrev domain FFCGX FiniteFieldCyclicGroupExtension
++ Authors: J.Grabmeier, A.Scheerhorn
++ Date Created: 04.04.1991
++ Basic Operations:
++ Related Constructors:  FiniteFieldCyclicGroupExtensionByPolynomial,
++  FiniteFieldPolynomialPackage
++ Also See: FiniteFieldExtension, FiniteFieldNormalBasisExtension
++ AMS Classifications:
++ Keywords: finite field, primitive elements, cyclic group
++ References:
++  R.Lidl, H.Niederreiter: Finite Field, Encycoldia of Mathematics and
++  Its Applications, Vol. 20, Cambridge Univ. Press, 1983, ISBN 0 521 30240 4
++  J. Grabmeier, A. Scheerhorn: Finite Fields in AXIOM.
++  AXIOM Technical Report Series, ATR/5 NP2522.
++ Description:
++  FiniteFieldCyclicGroupExtension(GF, n)  implements a extension of degree n
++  over the ground field {\em GF}. Its elements are represented by powers of
++  a primitive element, i.e. a generator of the multiplicative (cyclic) group.
++  As primitive element we choose the root of the extension polynomial, which
++  is created by {\em createPrimitivePoly} from
++  \spadtype{FiniteFieldPolynomialPackage}. Zech logarithms are stored
++  in a table of size half of the field size, and use \spadtype{SingleInteger}
++  for representing field elements, hence, there are restrictions
++  on the size of the field.


FiniteFieldCyclicGroupExtension(GF, extdeg) : _
  Exports == Implementation where
  GF       : FiniteFieldCategory
  extdeg   : PositiveInteger
  PI       ==> PositiveInteger
  FFPOLY         ==> FiniteFieldPolynomialPackage(GF)
  SI       ==> SingleInteger
  Exports  ==> FiniteAlgebraicExtensionField(GF) with
    getZechTable : () -> PrimitiveArray(SingleInteger)
      ++ getZechTable() returns the zech logarithm table of the field.
      ++ This table is used to perform additions in the field quickly.
  Implementation ==> FiniteFieldCyclicGroupExtensionByPolynomial(GF, _
                          createPrimitivePoly(extdeg)$FFPOLY)

)abbrev domain FFCG FiniteFieldCyclicGroup
++ Authors: J.Grabmeier, A.Scheerhorn
++ Date Created: 04.04.1991
++ Basic Operations:
++ Related Constructors:  FiniteFieldCyclicGroupExtensionByPolynomial,
++  FiniteFieldPolynomialPackage
++ Also See: FiniteField, FiniteFieldNormalBasis
++ AMS Classifications:
++ Keywords: finite field, primitive elements, cyclic group
++ References:
++  R.Lidl, H.Niederreiter: Finite Field, Encycoldia of Mathematics and
++  Its Applications, Vol. 20, Cambridge Univ. Press, 1983, ISBN 0 521 30240 4
++ Description:
++  FiniteFieldCyclicGroup(p, n) implements a finite field extension of degee n
++  over the prime field with p elements. Its elements are represented by
++  powers of a primitive element, i.e. a generator of the multiplicative
++  (cyclic) group. As primitive element we choose the root of the extension
++  polynomial, which is created by {\em createPrimitivePoly} from
++  \spadtype{FiniteFieldPolynomialPackage}. The Zech logarithms are stored
++  in a table of size half of the field size, and use \spadtype{SingleInteger}
++  for representing field elements, hence, there are restrictions
++  on the size of the field.

FiniteFieldCyclicGroup(p, extdeg) : _
  Exports == Implementation where
  p : PositiveInteger
  extdeg   : PositiveInteger
  PI       ==> PositiveInteger
  FFPOLY         ==> FiniteFieldPolynomialPackage(PrimeField(p))
  SI       ==> SingleInteger
  Exports  ==> FiniteAlgebraicExtensionField(PrimeField(p)) with
    getZechTable : () -> PrimitiveArray(SingleInteger)
      ++ getZechTable() returns the zech logarithm table of the field.
      ++ This table is used to perform additions in the field quickly.
  Implementation ==> FiniteFieldCyclicGroupExtensionByPolynomial(PrimeField(p), _
                          createPrimitivePoly(extdeg)$FFPOLY)

--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
--All rights reserved.
--
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are
--met:
--
--    - Redistributions of source code must retain the above copyright
--      notice, this list of conditions and the following disclaimer.
--
--    - Redistributions in binary form must reproduce the above copyright
--      notice, this list of conditions and the following disclaimer in
--      the documentation and/or other materials provided with the
--      distribution.
--
--    - Neither the name of The Numerical ALgorithms Group Ltd. nor the
--      names of its contributors may be used to endorse or promote products
--      derived from this software without specific prior written permission.
--
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
