/usr/share/axiom-20170501/src/algebra/FFHOM.spad is in axiom-source 20170501-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | )abbrev package FFHOM FiniteFieldHomomorphisms
++ Authors: J.Grabmeier, A.Scheerhorn
++ Date Created: 26.03.1991
++ References:
++ Grab92 Finite Fields in Axiom
++ Lidl83 Finite Field, Encyclopedia of Mathematics and Its Applications
++ Description:
++ FiniteFieldHomomorphisms(F1,GF,F2) exports coercion functions of
++ elements between the fields F1 and F2, which both must be
++ finite simple algebraic extensions of the finite ground field GF.
FiniteFieldHomomorphisms(F1,GF,F2) : SIG == CODE where
F1 : FiniteAlgebraicExtensionField(GF)
GF : FiniteFieldCategory
F2 : FiniteAlgebraicExtensionField(GF)
-- the homorphism can only convert elements w.r.t. the last extension .
-- Adding a function 'groundField()' which returns the groundfield of GF
-- as a variable of type FiniteFieldCategory in the new compiler, one
-- could build up 'convert' recursively to get an homomorphism w.r.t
-- the whole extension.
I ==> Integer
NNI ==> NonNegativeInteger
SI ==> SingleInteger
PI ==> PositiveInteger
SUP ==> SparseUnivariatePolynomial
M ==> Matrix GF
FFP ==> FiniteFieldExtensionByPolynomial
FFPOL2 ==> FiniteFieldPolynomialPackage2
FFPOLY ==> FiniteFieldPolynomialPackage
OUT ==> OutputForm
SIG ==> with
coerce : F1 -> F2
++ coerce(x) is the homomorphic image of x from
++ F1 in F2. Thus coerce is a
++ field homomorphism between the fields extensions
++ F1 and F2 both over ground field GF
++ (the second argument to the package).
++ Error: if the extension degree of F1 doesn't divide
++ the extension degree of F2.
++ Note that the other coercion function in the
++ \spadtype{FiniteFieldHomomorphisms} is a left inverse.
coerce : F2 -> F1
++ coerce(x) is the homomorphic image of x from
++ F2 in F1, where coerce is a
++ field homomorphism between the fields extensions
++ F2 and F1 both over ground field GF
++ (the second argument to the package).
++ Error: if the extension degree of F2 doesn't divide
++ the extension degree of F1.
++ Note that the other coercion function in the
++ \spadtype{FiniteFieldHomomorphisms} is a left inverse.
-- coerce(coerce(x:F1)@F2)@F1 = x and coerce(coerce(y:F2)@F1)@F2 = y
CODE ==> add
-- global variables ===================================================
degree1:NNI:= extensionDegree()$F1
degree2:NNI:= extensionDegree()$F2
-- the degrees of the last extension
-- a necessary condition for the one field being an subfield of
-- the other one is, that the respective extension degrees are
-- multiples
if max(degree1,degree2) rem min(degree1,degree2) ^= 0 then
error "FFHOM: one extension degree must divide the other one"
conMat1to2:M:= zero(degree2,degree1)$M
-- conversion Matix for the conversion direction F1 -> F2
conMat2to1:M:= zero(degree1,degree2)$M
-- conversion Matix for the conversion direction F2 -> F1
repType1:=representationType()$F1
repType2:=representationType()$F2
-- the representation types of the fields
init?:Boolean:=true
-- gets false after initialization
defPol1:=definingPolynomial()$F1
defPol2:=definingPolynomial()$F2
-- the defining polynomials of the fields
-- functions ==========================================================
compare: (SUP GF,SUP GF) -> Boolean
-- compares two polynomials
convertWRTsameDefPol12: F1 -> F2
convertWRTsameDefPol21: F2 -> F1
-- homomorphism if the last extension of F1 and F2 was build up
-- using the same defining polynomials
convertWRTdifferentDefPol12: F1 -> F2
convertWRTdifferentDefPol21: F2 -> F1
-- homomorphism if the last extension of F1 and F2 was build up
-- with different defining polynomials
initialize: () -> Void
-- computes the conversion matrices
compare(g:(SUP GF),f:(SUP GF)) ==
degree(f)$(SUP GF) >$NNI degree(g)$(SUP GF) => true
degree(f)$(SUP GF) <$NNI degree(g)$(SUP GF) => false
equal:Integer:=0
for i in degree(f)$(SUP GF)..0 by -1 while equal=0 repeat
not zero?(coefficient(f,i)$(SUP GF))$GF and _
zero?(coefficient(g,i)$(SUP GF))$GF => equal:=1
not zero?(coefficient(g,i)$(SUP GF))$GF and _
zero?(coefficient(f,i)$(SUP GF))$GF => equal:=(-1)
(f1:=lookup(coefficient(f,i)$(SUP GF))$GF) >$PositiveInteger _
(g1:=lookup(coefficient(g,i)$(SUP GF))$GF) => equal:=1
f1 <$PositiveInteger g1 => equal:=(-1)
equal=1 => true
false
initialize() ==
-- 1) in the case of equal def. polynomials initialize is called only
-- if one of the rep. types is "normal" and the other one is "polynomial"
-- we have to compute the basis change matrix 'mat', which i-th
-- column are the coordinates of a**(q**i), the i-th component of
-- the normal basis ('a' the root of the def. polynomial and q the
-- size of the groundfield)
defPol1 =$(SUP GF) defPol2 =>
-- new code using reducedQPowers
mat:=zero(degree1,degree1)$M
arr:=reducedQPowers(defPol1)$FFPOLY(GF)
for i in 1..degree1 repeat
setColumn_!(mat,i,vectorise(arr.(i-1),degree1)$SUP(GF))$M
-- old code
-- here one of the representation types must be "normal"
--a:=basis()$FFP(GF,defPol1).2 -- the root of the def. polynomial
--setColumn_!(mat,1,coordinates(a)$FFP(GF,defPol1))$M
--for i in 2..degree1 repeat
-- a:= a **$FFP(GF,defPol1) size()$GF
-- setColumn_!(mat,i,coordinates(a)$FFP(GF,defPol1))$M
--for the direction "normal" -> "polynomial" we have to multiply the
-- coordinate vector of an element of the normal basis field with
-- the matrix 'mat'. In this case 'mat' is the correct conversion
-- matrix for the conversion of F1 to F2, its inverse the correct
-- inversion matrix for the conversion of F2 to F1
repType1 = "normal" => -- repType2 = "polynomial"
conMat1to2:=copy(mat)
conMat2to1:=copy(inverse(mat)$M :: M)
--finish the function for one case, hence reset initialization flag
init? := false
void()$Void
-- print("'normal' <=> 'polynomial' matrices initialized"::OUT)
-- in the other case we have to change the matrices
-- repType2 = "normal" and repType1 = "polynomial"
conMat2to1:=copy(mat)
conMat1to2:=copy(inverse(mat)$M :: M)
-- print("'normal' <=> 'polynomial' matrices initialized"::OUT)
--we finish the function for one case, hence reset initialization flag
init? := false
void()$Void
-- 2) in the case of different def. polynomials we have to order the
-- fields to get the same isomorphism, if the package is called with
-- the fields F1 and F2 swapped.
dPbig:= defPol2
rTbig:= repType2
dPsmall:= defPol1
rTsmall:= repType1
degbig:=degree2
degsmall:=degree1
if compare(defPol2,defPol1) then
degsmall:=degree2
degbig:=degree1
dPbig:= defPol1
rTbig:= repType1
dPsmall:= defPol2
rTsmall:= repType2
-- 3) in every case we need a conversion between the polynomial
-- represented fields. Therefore we compute 'root' as a root of the
-- 'smaller' def. polynomial in the 'bigger' field.
-- We compute the matrix 'matsb', which i-th column are the coordinates
-- of the (i-1)-th power of root, i=1..degsmall. Multiplying a
-- coordinate vector of an element of the 'smaller' field by this
-- matrix, we got the coordinates of the corresponding element in the
-- 'bigger' field.
-- compute the root of dPsmall in the 'big' field
root:=rootOfIrreduciblePoly(dPsmall)$FFPOL2(FFP(GF,dPbig),GF)
-- set up matrix for polynomial conversion
matsb:=zero(degbig,degsmall)$M
qsetelt_!(matsb,1,1,1$GF)$M
a:=root
for i in 2..degsmall repeat
setColumn_!(matsb,i,coordinates(a)$FFP(GF,dPbig))$M
a := a *$FFP(GF,dPbig) root
-- the conversion from 'big' to 'small': we can't invert matsb
-- directly, because it has degbig rows and degsmall columns and
-- may be no square matrix. Therfore we construct a square matrix
-- mat from degsmall linear independent rows of matsb and invert it.
-- Now we get the conversion matrix 'matbs' for the conversion from
-- 'big' to 'small' by putting the columns of mat at the indices
-- of the linear independent rows of matsb to columns of matbs.
ra:I:=1 -- the rank
mat:M:=transpose(row(matsb,1))$M -- has already rank 1
rowind:I:=2
iVec:Vector I:=new(degsmall,1$I)$(Vector I)
while ra < degsmall repeat
if rank(vertConcat(mat,transpose(row(matsb,rowind))$M)$M)$M > ra then
mat:=vertConcat(mat,transpose(row(matsb,rowind))$M)$M
ra:=ra+1
iVec.ra := rowind
rowind:=rowind + 1
mat:=inverse(mat)$M :: M
matbs:=zero(degsmall,degbig)$M
for i in 1..degsmall repeat
setColumn_!(matbs,iVec.i,column(mat,i)$M)$M
-- print(matsb::OUT)
-- print(matbs::OUT)
-- 4) if the 'bigger' field is "normal" we have to compose the
-- polynomial conversion with a conversion from polynomial to normal
-- between the FFP(GF,dPbig) and FFNBP(GF,dPbig) the 'bigger'
-- field. Therefore we compute a conversion matrix 'mat' as in 1)
-- Multiplying with the inverse of 'mat' yields the desired
-- conversion from polynomial to normal. Multiplying this matrix by
-- the above computed 'matsb' we got the matrix for converting form
-- 'small polynomial' to 'big normal'.
-- set up matrix 'mat' for polynomial to normal
if rTbig = "normal" then
arr:=reducedQPowers(dPbig)$FFPOLY(GF)
mat:=zero(degbig,degbig)$M
for i in 1..degbig repeat
setColumn_!(mat,i,vectorise(arr.(i-1),degbig)$SUP(GF))$M
-- old code
--a:=basis()$FFP(GF,dPbig).2 -- the root of the def.Polynomial
--setColumn_!(mat,1,coordinates(a)$FFP(GF,dPbig))$M
--for i in 2..degbig repeat
-- a:= a **$FFP(GF,dPbig) size()$GF
-- setColumn_!(mat,i,coordinates(a)$FFP(GF,dPbig))$M
-- print(inverse(mat)$M::OUT)
matsb:= (inverse(mat)$M :: M) * matsb
-- print("inv *.."::OUT)
matbs:=matbs * mat
-- 5) if the 'smaller' field is "normal" we have first to convert
-- from 'small normal' to 'small polynomial', that is from
-- FFNBP(GF,dPsmall) to FFP(GF,dPsmall). Therefore we compute a
-- conversion matrix 'mat' as in 1). Multiplying with 'mat'
-- yields the desired conversion from normal to polynomial.
-- Multiplying the above computed 'matsb' with 'mat' we got the
-- matrix for converting form 'small normal' to 'big normal'.
-- set up matrix 'mat' for normal to polynomial
if rTsmall = "normal" then
arr:=reducedQPowers(dPsmall)$FFPOLY(GF)
mat:=zero(degsmall,degsmall)$M
for i in 1..degsmall repeat
setColumn_!(mat,i,vectorise(arr.(i-1),degsmall)$SUP(GF))$M
-- old code
--b:FFP(GF,dPsmall):=basis()$FFP(GF,dPsmall).2
--setColumn_!(mat,1,coordinates(b)$FFP(GF,dPsmall))$M
--for i in 2..degsmall repeat
-- b:= b **$FFP(GF,dPsmall) size()$GF
-- setColumn_!(mat,i,coordinates(b)$FFP(GF,dPsmall))$M
-- print(mat::OUT)
matsb:= matsb * mat
matbs:= (inverse(mat) :: M) * matbs
-- now 'matsb' is the corret conversion matrix for 'small' to 'big'
-- and 'matbs' the corret one for 'big' to 'small'.
-- depending on the above ordering the conversion matrices are
-- initialized
dPbig =$(SUP GF) defPol2 =>
conMat1to2 :=matsb
conMat2to1 :=matbs
-- print(conMat1to2::OUT)
-- print(conMat2to1::OUT)
-- print("conversion matrices initialized"::OUT)
--we finish the function for one case, hence reset initialization flag
init? := false
void()$Void
conMat1to2 :=matbs
conMat2to1 :=matsb
-- print(conMat1to2::OUT)
-- print(conMat2to1::OUT)
-- print("conversion matrices initialized"::OUT)
--we finish the function for one case, hence reset initialization flag
init? := false
void()$Void
coerce(x:F1) ==
inGroundField?(x)$F1 => retract(x)$F1 :: F2
-- if x is already in GF then we can use a simple coercion
defPol1 =$(SUP GF) defPol2 => convertWRTsameDefPol12(x)
convertWRTdifferentDefPol12(x)
convertWRTsameDefPol12(x:F1) ==
repType1 = repType2 => x pretend F2
-- same groundfields, same defining polynomials, same
-- representation types --> F1 = F2, x is already in F2
repType1 = "cyclic" =>
x = 0$F1 => 0$F2
-- the SI corresponding to the cyclic representation is the exponent of
-- the primitiveElement, therefore we exponentiate the primitiveElement
-- of F2 by it.
primitiveElement()$F2 **$F2 (x pretend SI)
repType2 = "cyclic" =>
x = 0$F1 => 0$F2
-- to get the exponent, we have to take the discrete logarithm of the
-- element in the given field.
(discreteLog(x)$F1 pretend SI) pretend F2
-- here one of the representation types is "normal"
if init? then initialize()
-- here a conversion matrix is necessary, (see initialize())
represents(conMat1to2 *$(Matrix GF) coordinates(x)$F1)$F2
convertWRTdifferentDefPol12(x:F1) ==
if init? then initialize()
-- if we want to convert into a 'smaller' field, we have to test,
-- whether the element is in the subfield of the 'bigger' field, which
-- corresponds to the 'smaller' field
if degree1 > degree2 then
if positiveRemainder(degree2,degree(x)$F1)^= 0 then
error "coerce: element doesn't belong to smaller field"
represents(conMat1to2 *$(Matrix GF) coordinates(x)$F1)$F2
-- the three functions below equal the three functions above up to
-- '1' exchanged by '2' in all domain and variable names
coerce(x:F2) ==
inGroundField?(x)$F2 => retract(x)$F2 :: F1
-- if x is already in GF then we can use a simple coercion
defPol1 =$(SUP GF) defPol2 => convertWRTsameDefPol21(x)
convertWRTdifferentDefPol21(x)
convertWRTsameDefPol21(x:F2) ==
repType1 = repType2 => x pretend F1
-- same groundfields, same defining polynomials,
-- same representation types --> F1 = F2, that is:
-- x is already in F1
repType2 = "cyclic" =>
x = 0$F2 => 0$F1
primitiveElement()$F1 **$F1 (x pretend SI)
repType1 = "cyclic" =>
x = 0$F2 => 0$F1
(discreteLog(x)$F2 pretend SI) pretend F1
-- here one of the representation types is "normal"
if init? then initialize()
represents(conMat2to1 *$(Matrix GF) coordinates(x)$F2)$F1
convertWRTdifferentDefPol21(x:F2) ==
if init? then initialize()
if degree2 > degree1 then
if positiveRemainder(degree1,degree(x)$F2)^= 0 then
error "coerce: element doesn't belong to smaller field"
represents(conMat2to1 *$(Matrix GF) coordinates(x)$F2)$F1
|