1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancments. ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; (c) Copyright 1981 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 ;;; *****************************************************************
14 ;;; ***** NUMTH ******* VARIOUS NUMBER THEORY FUNCTIONS *************
15 ;;; *****************************************************************
17 (macsyma-module numth
)
19 (declare-top (special $intfaclim
))
21 (load-macsyma-macros rzmac
)
23 ;;; Sum of divisors and Totient functions
25 (defmfun $divsum
(n &optional
(k 1))
26 (let (($intfaclim nil
))
27 (if (and (integerp k
) (integerp n
))
33 (do ((l (cfactorw n
) (cddr l
))
34 (a 1 (* a
(1+ (cadr l
)))))
37 `((rat) ,(divsum (cfactorw n
) (- k
)) ,(expt n
(- k
))))
39 (divsum (cfactorw n
) k
))))
40 (list '($divsum
) n k
))))
46 (unless (eql (car l
) 1)
47 (let ((temp (expt (car l
) k
)))
49 (truncate (1- (expt temp
(1+ (cadr l
))))
59 (t (do ((factors (let ($intfaclim
) (cfactorw n
))
61 (total 1 (* total
(1- (car factors
))
62 (expt (car factors
) (1- (cadr factors
))))))
63 ((null factors
) total
)))))
64 (t (list '($totient
) n
))))
67 ;;; JACOBI symbol and Gaussian factoring
69 (declare-top (special modulus $intfaclim
))
71 (defvar *incl
* (let ((l (list 2 4))) (nconc l l
)))
75 ((not (= (rem p
4) 1)) nil
)
76 ((= (rem p
8) 5) (imodp1 2 p
))
77 ((= (rem p
24) 17) (imodp1 3 p
)) ;p=2(mod 3)
78 (t (do ((i 5 (+ i
(car j
))) ;p=1(mod 24)
80 ((= (jacobi i p
) -
1) (imodp1 i p
))))))
82 (defun imodp1 (i modulus
)
83 (abs (cexpt i
(ash (1- modulus
) -
2) )))
88 ((equal p
2) (list 1 1))
96 ((not (> r1 sp
)) (list r1 r2
))))
98 (defun gctimes (a b c d
)
99 (list (- (* a c
) (* b d
))
100 (+ (* a d
) (* b c
))))
102 (defmfun $gcfactor
(n)
103 (let ((n (cdr ($totaldisrep
($bothcoef
($rat n
'$%i
) '$%i
)))))
104 (if (not (and (integerp (car n
)) (integerp (cadr n
))))
105 (gcdisp (nreverse n
))
106 (do ((factors (gcfactor (cadr n
) (car n
)) (cddr factors
))
111 ((null (cdr res
)) (car res
))
112 (t (cons '(mtimes simp
) (nreverse res
)))))
113 (let ((term (car factors
))
114 (exp (cadr factors
)))
117 (pow (gcdisp term
) exp
))
123 ((let ((rp (car term
))
125 (setq ip
(if (equal ip
1) '$%i
(list '(mtimes) ip
'$%i
)))
128 (list '(mplus) rp ip
))))))
130 (defun gcfactor (a b
)
131 (prog (gl cd dc econt p e1 e2 ans plis nl $intfaclim
)
138 nl
(cfactorw (+ (* a a
) (* b b
)))
140 (and (equal 1 (car gl
)) (setq gl nil
))
141 (and (equal 1 (car nl
)) (setq nl nil
))
144 (cond ((null nl
) (go ret
))
145 ((setq p
(car nl
)))))
146 ((null nl
) (setq p
(car gl
)))
147 (t (setq p
(max (car gl
) (car nl
)))))
150 (setq plis
(cons p
(cons (cadr gl
) plis
)))
154 (cond ((zerop (rem (+ (* a
(car cd
)) ;gcremainder
156 p
)) ;remainder(real((a+bi)cd~),p)
157 ;z~ is complex conjugate
158 (setq e1
(cadr nl
)) (setq dc cd
))
159 (t (setq e2
(cadr nl
))
160 (setq dc
(reverse cd
))))
161 (setq dc
(gcexpt dc
(cadr nl
)) ;
162 dc
(gctimes a b
(car dc
) (- (cadr dc
)))
163 a
(quotient (car dc
) p
)
164 b
(quotient (cadr dc
) p
)
166 (cond ((equal p
(car gl
))
167 (setq econt
(+ econt
(cadr gl
)))
169 (setq e1
(+ e1
(* 2 (cadr gl
)))))
170 (t (setq e1
(+ e1
(cadr gl
))
171 e2
(+ e2
(cadr gl
)))))
172 (setq gl
(cddr gl
))))
173 (and (not (zerop e1
))
174 (setq ans
(cons cd
(cons e1 ans
)))
176 (and (not (zerop e2
))
177 (setq ans
(cons (reverse cd
) (cons e2 ans
)))
181 (setq cd
(gcexpt (list 0 -
1)
183 (setq a
(gctimes a b
(car cd
) (cadr cd
)))
184 ;;a hasn't been divided by p yet..
185 (setq a
(mapcar 'signum a
))
186 #+cl
(assert (or (zerop (car a
))(zerop (second a
))))
187 (cond ((or (equal (car a
) -
1) (equal (cadr a
) -
1))
188 (setq plis
(cons -
1 (cons 1 plis
)))))
189 (cond ((equal (car a
) 0)
190 (setq ans
(cons '(0 1) (cons 1 ans
)))))
191 (setq ans
(nconc plis ans
))
194 (defun multiply-gcfactors (lis)
195 (loop for
(term exp
) on
(cddr lis
) by
#'cddr
196 with answ
= (cond ((numberp (car lis
))(list (pexpt (car lis
) (second lis
)) 0))
197 (t(gcexpt (car lis
) (second lis
))))
199 do
(setq answ
(list (* (first answ
) term
) (* (second answ
) term
)))
202 do
(setq answ
(apply 'gctimes
(append answ
(gcexpt term exp
))))
203 finally
(return answ
)))
206 (cond ((zerop n
) '(1 0))
208 ((evenp n
) (gcexpt (gctime1 a a
) (truncate n
2)))
209 (t (gctime1 a
(gcexpt (gctime1 a a
) (truncate n
2))))))
212 (gctimes (car a
) (cadr a
) (car b
) (cadr b
)))
215 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
217 ;; Maxima functions in (Z/nZ)*
219 ;; zn_order, zn_primroot_p, zn_primroot, zn_log,
220 ;; chinese, zn_characteristic_factors, zn_factor_generators, zn_nth_root,
221 ;; zn_add_table, zn_mult_table, zn_power_table
223 ;; 2012 - 2015, Volker van Nek
226 ;; Maxima option variables:
227 (defmvar $zn_primroot_limit
1000 "Upper bound for `zn_primroot'." fixnum
)
228 (defmvar $zn_primroot_verbose nil
"Print message when `zn_primroot_limit' is reached." boolean
)
229 (defmvar $zn_primroot_pretest nil
"`zn_primroot' pretests whether (Z/nZ)* is cyclic." boolean
)
232 (defun zn-quo (n d p
)
234 (mod (* n
(inv-mod d p
)) p
) )
237 ;; compute the order of x in (Z/nZ)*
239 ;; optional argument: ifactors of totient(n) as returned in Maxima by
240 ;; block([factors_only:false], ifactors(totient(n)))
241 ;; e.g. [[2, 3], [3, 1], ... ]
243 (defmfun $zn_order
(x n
&optional fs-phi
)
244 (unless (and (integerp x
) (integerp n
))
245 (return-from $zn_order
247 (list '($zn_order
) x n fs-phi
)
248 (list '($zn_order
) x n
) )))
252 ((= 1 x
) (if (= n
1) nil
1))
253 ((/= 1 (gcd x n
)) nil
)
256 (if (and ($listp fs-phi
) ($listp
(cadr fs-phi
)))
258 (setq fs-phi
(mapcar #'cdr
(cdr fs-phi
))) ; Lispify fs-phi
259 (setq fs-phi
(cons (totient-from-factors fs-phi
) fs-phi
)) )
260 (gf-merror (intl:gettext
261 "Third argument to `zn_order' must be of the form [[p1, e1], ..., [pk, ek]]." )))
262 (setq fs-phi
(totient-with-factors n
)) )
266 (cdr fs-phi
)) ))) ;; factors of phi with multiplicity
268 (defun zn_order (x n phi fs-phi
)
269 (format t
"`zn_order' is deprecated. ~%Please use `zn-order' instead.~%" )
270 (zn-order x n phi fs-phi
) )
272 ;; compute order of x as a divisor of the known group order
274 (defun zn-order (x n ord fs-ord
)
276 (dolist (f fs-ord ord
)
277 (setq p
(car f
) e
(cadr f
)
278 ord
(truncate ord
(expt p e
))
279 z
(power-mod x ord n
) )
280 ;; ord(z) = p^i, i from [0,e]
281 ;; replace p^e in ord by p^i : x^(ord*p^i/p^e) = 1
285 (when (= e
1) (return))
287 (setq z
(power-mod z p n
)) ))))
290 ;; compute totient (euler-phi) of n and its factors in one function
292 ;; returns a list of the form (phi ((p1 e1) ... (pk ek)))
294 (defun totient-with-factors (n)
295 (let (($intfaclim
) (phi 1) fs-n
(fs) p e
(fs-phi) g
)
296 (setq fs-n
(get-factor-list n
))
298 (setq p
(car f
) e
(cadr f
))
299 (setq phi
(* phi
(1- p
) (expt p
(1- e
))))
300 (when (> e
1) (setq fs
(cons `(,p
,(1- e
)) fs
)))
301 (setq fs
(append (get-factor-list (1- p
)) fs
)) )
302 (setq fs
(copy-tree fs
)) ;; this deep copy is a workaround to avoid references
303 ;; to the list returned by ifactor.lisp/get-factor-list.
305 (setq fs
(sort fs
#'< :key
#'car
))
307 (dolist (f (cdr fs
) (cons phi
(reverse (cons g fs-phi
))))
308 (if (= (car f
) (car g
))
309 (incf (cadr g
) (cadr f
)) ;; assignment
311 (setq fs-phi
(cons g fs-phi
))
314 ;; recompute totient from given factors
316 ;; fs-phi: factors of totient with multiplicity: ((p1 e1) ... (pk ek))
318 (defun totient-from-factors (fs-phi)
320 (dolist (f fs-phi phi
)
321 (setq p
(car f
) e
(cadr f
))
322 (setq phi
(* phi
(expt p e
))) )))
325 ;; for n > 2 is x a primitive root modulo n
326 ;; when n does not divide x
327 ;; and for all prime factors p of phi = totient(n)
328 ;; x^(phi/p) mod n # 1
330 ;; optional argument: ifactors of totient(n)
332 (defmfun $zn_primroot_p
(x n
&optional fs-phi
)
333 (unless (and (integerp x
) (integerp n
))
334 (return-from $zn_primroot_p
336 (list '($zn_primroot_p
) x n fs-phi
)
337 (list '($zn_primroot_p
) x n
) )))
341 ((= 1 x
) (if (= n
2) t nil
))
345 (if (and ($listp fs-phi
) ($listp
(cadr fs-phi
)))
347 (setq fs-phi
(mapcar #'cdr
(cdr fs-phi
))) ; Lispify fs-phi
348 (setq fs-phi
(cons (totient-from-factors fs-phi
) fs-phi
)) )
349 (gf-merror (intl:gettext
350 "Third argument to `zn_primroot_p' must be of the form [[p1, e1], ..., [pk, ek]]." )))
351 (setq fs-phi
(totient-with-factors n
)) )
354 (mapcar #'car
(cdr fs-phi
))) ))) ;; factors only (omitting multiplicity)
356 (defun zn-primroot-p (x n phi fs-phi
)
357 (unless (= 1 (gcd x n
))
358 (return-from zn-primroot-p nil
) )
360 (when (= 1 (power-mod x
(truncate phi p
) n
))
361 (return-from zn-primroot-p nil
) )))
364 ;; find the smallest primitive root modulo n
366 ;; optional argument: ifactors of totient(n)
368 (defmfun $zn_primroot
(n &optional fs-phi
)
370 (return-from $zn_primroot
372 (list '($zn_primroot
) n fs-phi
)
373 (list '($zn_primroot
) n
) )))
378 (when $zn_primroot_pretest
380 (return-from $zn_primroot nil
) ))
382 (if (and ($listp fs-phi
) ($listp
(cadr fs-phi
)))
384 (setq fs-phi
(mapcar #'cdr
(cdr fs-phi
))) ; Lispify fs-phi
385 (setq fs-phi
(cons (totient-from-factors fs-phi
) fs-phi
)) )
386 (gf-merror (intl:gettext
387 "Second argument to `zn_primroot' must be of the form [[p1, e1], ..., [pk, ek]]." )))
388 (setq fs-phi
(totient-with-factors n
)) )
391 (mapcar #'car
(cdr fs-phi
))) ))) ;; factors only (omitting multiplicity)
393 ;; (Z/nZ)* is cyclic if n = 2, 4, p^k or 2*p^k where p prime > 2
396 (when (< n
2) (return))
397 (when (< n
8) (return t
)) ;; 2,3,4,5,2*3,7
398 (when (evenp n
) ;; 2*p^k
399 (setq n
(ash n -
1)) ;; -> p^k
400 (when (evenp n
) (return)) )
401 (let (($intfaclim
) fs
(len 0))
402 (multiple-value-setq (n fs
) (get-small-factors n
))
403 (when fs
(setq len
(length fs
)))
404 (when (= 1 n
) (return (= 1 len
)))
405 (when (> len
0) (return))
406 (when (primep n
) (return t
))
407 (setq fs
(convert-list (get-large-factors n
)))
408 (return (= 1 (length fs
))) )))
410 (defun zn-primroot (n phi fs-phi
)
413 (when (zn-primroot-p i n phi fs-phi
)
415 (when (= i $zn_primroot_limit
)
416 (when $zn_primroot_verbose
417 (format t
"`zn_primroot' stopped at zn_primroot_limit = ~A~%" $zn_primroot_limit
) )
421 ;; Chinese Remainder Theorem
423 (defmfun $chinese
(rems mods
&optional
(return-lcm? nil
))
425 ((not (and ($listp rems
) ($listp mods
)))
426 (list '($chinese
) rems mods
) )
427 ((let ((lr ($length rems
)) (lm ($length mods
)))
428 (or (= 0 lr
) (= 0 lm
) (/= lr lm
)) )
429 (gf-merror (intl:gettext
430 "Unsuitable arguments to `chinese': ~m ~m" ) rems mods
))
431 ((notevery #'integerp
(setq rems
(cdr rems
)))
432 (list '($chinese
) (cons '(mlist simp
) rems
) mods
) )
433 ((notevery #'integerp
(setq mods
(cdr mods
)))
434 (list '($chinese
) (cons '(mlist simp
) rems
) (cons '(mlist simp
) mods
)) )
435 ((eql return-lcm?
'$lcm
)
436 (cons '(mlist simp
) (chinese rems mods
)) )
438 (car (chinese rems mods
)) )))
440 (defun chinese (rems mods
)
441 (if (= 1 (length mods
))
442 (list (car rems
) (car mods
))
443 (let ((rp (car rems
))
445 (rq-q (chinese (cdr rems
) (cdr mods
))) )
447 (let* ((rq (car rq-q
))
451 (c (cadr gc
)) ) ;; CRT-coefficient
453 ((= 1 g
) ;; coprime moduli
454 (let* ((h (mod (* (- rp rq
) c
) p
))
457 ((= 0 (mod (- rp rq
) g
)) ;; ensures unique solution
458 (let* ((h (* (- rp rq
) c
))
461 (list (mod (+ rq
(* h q
/g
)) lcm-pq
) lcm-pq
) ))))))))
463 ;; (zn-gcdex2 x y) returns `(,g ,c) where c*x + d*y = g = gcd(x,y)
465 (defun zn-gcdex2 (x y
)
466 (let ((x1 1) (y1 0) q r
)
467 (do ()((= 0 y
) (list x x1
))
468 (multiple-value-setq (q r
) (truncate x y
))
470 (psetf x1 y1 y1
(- x1
(* q y1
))) )))
473 ;; discrete logarithm:
474 ;; solve g^x = a mod n, where g is a generator of (Z/nZ)*
476 ;; see: lecture notes 'Grundbegriffe der Kryptographie' - Eike Best
477 ;; http://theoretica.informatik.uni-oldenburg.de/~best/publications/kry-Mai2005.pdf
479 ;; optional argument: ifactors of totient(n)
481 (defmfun $zn_log
(a g n
&optional fs-phi
)
482 (unless (and (integerp a
) (integerp g
) (integerp n
))
485 (list '($zn_log
) a g n fs-phi
)
486 (list '($zn_log
) a g n
) )))
487 (when (minusp a
) (setq a
(mod a n
)))
489 ((or (= 0 a
) (>= a n
)) nil
)
492 ((> (gcd a n
) 1) nil
)
495 (if (and ($listp fs-phi
) ($listp
(cadr fs-phi
)))
497 (setq fs-phi
(mapcar #'cdr
(cdr fs-phi
))) ; Lispify fs-phi
498 (setq fs-phi
(cons (totient-from-factors fs-phi
) fs-phi
)) )
499 (gf-merror (intl:gettext
500 "Fourth argument to `zn_log' must be of the form [[p1, e1], ..., [pk, ek]]." )))
501 (setq fs-phi
(totient-with-factors n
)) )
503 ((not (zn-primroot-p g n
505 (mapcar #'car
(cdr fs-phi
)) )) ;; factors without multiplicity
506 (gf-merror (intl:gettext
507 "Second argument to `zn_log' must be a generator of (Z/~MZ)*." ) n
))
508 ((= 0 (mod (- a
(* g g
)) n
))
510 ((= 1 (mod (* a g
) n
))
511 (mod -
1 (car fs-phi
)) )
515 (cdr fs-phi
) ) ))))) ;; factors with multiplicity
517 ;; Pohlig-Hellman-reduction:
519 ;; Solve g^x = a mod n.
520 ;; Assume, that a is an element of (Z/nZ)* and g is a generator.
522 (defun zn-dlog (a g n ord fs-ord
)
523 (let (p e ord
/p om xp xk mods dlogs
(g-inv (inv-mod g n
)))
525 (setq p
(car f
) e
(cadr f
)
526 ord
/p
(truncate ord p
)
527 om
(power-mod g ord
/p n
) ;; om is a generator of prime order p
529 ;; Let op = ord/p^e, gp = g^op (mod n), ap = a^op (mod n) and
531 ;; gp is of order p^e and therefore
532 ;; (*) gp^xp = ap (mod n).
533 (do ((b a
) (k 0) (pk 1) (acc g-inv
) (e1 (1- e
))) (()) ;; Solve (*) by solving e logs ..
534 (setq xk
(dlog-rho (power-mod b ord
/p n
) om p n
)) ;; .. in subgroups of order p.
537 (when (= k e
) (return)) ;; => xp = x_0+x_1*p+x_2*p^2+...+x_{e-1}*p^{e-1} < p^e
538 (setq ord
/p
(truncate ord
/p p
)
540 (when (/= xk
0) (setq b
(mod (* b
(power-mod acc xk n
)) n
)))
541 (when (/= k e1
) (setq acc
(power-mod acc p n
))) )
542 (push (expt p e
) mods
)
544 (car (chinese dlogs mods
)) )) ;; Find x (mod ord) with x = xp (mod p^e) for all p,e.
546 ;; baby-steps-giant-steps:
548 (defun dlog-baby-giant (a g p n
) ;; g is generator of order p mod n
549 (let* ((m (1+ (isqrt p
)))
550 (s (floor (* 1.3 m
)))
554 (make-hash-table :size s
:test
#'eql
:rehash-threshold
0.9) )
559 (return-from dlog-baby-giant r
) )
560 (setf (gethash b babies
) r
)
562 (when (= r m
) (return))
563 (setq b
(mod (* gi b
) n
)) )
564 (setq g^m
(power-mod g m n
))
566 (bb 1 (mod (* g^m bb
) n
))
568 (when (setq r
(gethash bb babies
))
570 (return (+ (* rr m
) r
)) )) ))
574 (defun dlog-naive (a g n
)
575 (do ((i 0 (1+ i
)) (gi 1 (mod (* gi g
) n
)))
578 ;; Pollard rho for dlog computation (Brents variant of collision detection)
580 (defun dlog-rho (a g p n
) ;; g is generator of prime order p mod n
584 ((= 0 (mod (- a
(* g g
)) n
)) 2)
585 ((= 1 (mod (* a g
) n
)) (1- p
))
586 ((< p
512) (dlog-naive a g n
))
587 ((< p
65536) (dlog-baby-giant a g p n
))
589 (prog ((b 1) (y 0) (z 0) ;; b = g^y * a^z
590 (bb 1) (yy 0) (zz 0) ;; bb = g^yy * a^zz
593 (do ((i 0)(j 1)) (()) (declare (fixnum i j
))
594 (multiple-value-setq (b y z
) (dlog-f b y z a g p n
))
595 (when (equal b bb
) (return)) ;; g^y * a^z = g^yy * a^zz
598 (setq j
(1+ (ash j
1)))
599 (setq bb b yy y zz z
) ))
600 (setq dy
(mod (- y yy
) p
) dz
(mod (- zz z
) p
)) ;; g^dy = a^dz = g^(x*dz)
601 (when (= 1 (gcd dz p
))
602 (return (zn-quo dy dz p
)) ) ;; x = dy/dz mod p (since g is generator of order p)
606 yy
(1+ (random (1- p
)))
607 zz
(1+ (random (1- p
)))
608 bb
(mod (* (power-mod g yy n
) (power-mod a zz n
)) n
) )
611 ;; iteration for Pollard rho: b = g^y * a^z in each step
613 (defun dlog-f (b y z a g ord n
)
617 (values (mod (* b b
) n
) (mod (ash y
1) ord
) (mod (ash z
1) ord
)) )
618 ((= 1 m
) ;; avoid stationary case b=1 => b*b=1
619 (values (mod (* a b
) n
) y
(mod (+ z
1) ord
) ) )
621 (values (mod (* g b
) n
) (mod (+ y
1) ord
) z
) ) )))
624 ;; characteristic factors:
626 (defmfun $zn_characteristic_factors
(m)
627 (unless (and (integerp m
) (> m
1)) ;; according to Shanks no result for m = 1
628 (gf-merror (intl:gettext
629 "`zn_characteristic_factors': Argument must be an integer greater than 1." )))
630 (cons '(mlist simp
) (zn-characteristic-factors m
)) )
632 (defmfun $zn_carmichael_lambda
(m)
635 (if (= m
1) 1 (zn-characteristic-factors m t
)) )
636 (t (gf-merror (intl:gettext
637 "`zn_carmichael_lambda': Argument must be a positive integer." )))))
639 ;; D. Shanks - Solved and unsolved problems in number theory, 2. ed
640 ;; definition 29 and 30 (p. 92 - 94)
642 ;; (zn-characteristic-factors 104) --> (2 2 12)
643 ;; => Z104* is isomorphic to M2 x M2 x M12
644 ;; the direct product of modulo multiplication groups of order 2 resp. 12
646 (defun zn-characteristic-factors (m &optional lambda-only
) ;; m > 1
648 (pe-list (get-factor-list m
)) ;; def. 29 part A
649 (shanks-phi ;; part D
651 (apply #'nconc
(mapcar #'zn-shanks-phi-step-bc pe-list
))
654 (do ((todo shanks-phi
(nreverse left
))
655 (p 0 0) (f 1 1) (left nil nil
)
659 (setq q
(car qd
) d
(cadr qd
))
662 (setq p q f
(* f
(expt q d
))) ))
663 (when lambda-only
(return-from zn-characteristic-factors f
))
666 ;; definition 29 parts B,C (p. 92)
667 (defun zn-shanks-phi-step-bc (pe)
668 (let ((p (car pe
)) (e (cadr pe
)) qd
)
671 (setq qd
(list (if (> e
1) '(2 1) '(1 1))))
672 (when (> e
2) (setq qd
(nconc qd
(list `(2 ,(- e
2)))))) )
674 (setq qd
(let (($intfaclim
)) (get-factor-list (1- p
))))
676 (setq qd
(nconc qd
(list `(,p
,(1- e
))))) )))
680 (cond ((> (car a
) (car b
)) t
)
681 ((< (car a
) (car b
)) nil
)
682 (t (> (cadr a
) (cadr b
))) ))
685 ;; factor generators:
687 (defmfun $zn_factor_generators
(m)
688 (unless (and (integerp m
) (> m
1))
689 (gf-merror (intl:gettext
690 "`zn_factor_generators': Argument must be an integer greater or equal 2." )))
691 (cons '(mlist simp
) (zn-factor-generators m
)) )
693 ;; D. Shanks - Solved and unsolved problems in number theory, 2. ed
694 ;; Theorem 44, page 94
696 ;; zn_factor_generators(104); --> [79,27,89]
697 ;; zn_characteristic_factors(104); --> [2,2,12]
698 ;; map(lambda([g], zn_order(g,104)), [79,27,89]); --> [2,2,12]
700 ;; Every element in Z104* can be expressed as
701 ;; 79^i * 27^j * 89^k (mod m) where 0 <= i,j < 2 and 0 <= k < 12
703 ;; The proof of theorem 44 contains the construction of the factor generators.
705 (defun zn-factor-generators (m) ;; m > 1
707 (fs (sort (get-factor-list m
) #'< :key
#'car
))
709 (p (car pe
)) (e (cadr pe
))
711 phi fs-phi ga gs ords fs-ords pegs
)
712 ;; lemma 1, page 98 :
713 ;; (Z/mZ)* is cyclic when m =
715 (return-from zn-factor-generators
(list 1)) )
716 (when (or (< m
8) ;; 3,4,5,6,7
717 (and (> p
2) (null (cdr fs
))) ;; p^k, p#2
718 (and (= 2 p
) (= 1 e
) (null (cddr fs
))) ) ;; 2*p^k, p#2
719 (setq phi
(totient-by-fs-n fs
)
720 fs-phi
(sort (mapcar #'car
(get-factor-list phi
)) #'<)
721 ga
(zn-primroot m phi fs-phi
) )
722 (return-from zn-factor-generators
(list ga
)) )
726 (unless (and (= e
1) (cdr fs
)) ;; phi(2*m) = phi(m) if m#1 is odd
727 (push (1- a
) gs
) ) ;; a = 2^e
728 (when (> e
1) (setq ords
(list 2) fs-ords
(list '((2 1)))))
730 (push 3 gs
) (push (expt 2 (- e
2)) ords
) (push `((2 ,(- e
2))) fs-ords
) ))
731 ;; lemma 2, page 100 :
733 (setq phi
(* (1- p
) (expt p
(1- e
)))
734 fs-phi
(sort (get-factor-list (1- p
)) #'< :key
#'car
) )
735 (when (> e
1) (setq fs-phi
(nconc fs-phi
(list `(,p
,(1- e
))))))
736 (setq ga
(zn-primroot a phi
(mapcar #'car fs-phi
)) ;; factors only
739 fs-ords
(list fs-phi
) )))
743 (setq pe
(car fs
) fs
(cdr fs
)
744 p
(car pe
) e
(cadr pe
)
745 phi
(* (1- p
) (expt p
(1- e
)))
746 fs-phi
(sort (get-factor-list (1- p
)) #'< :key
#'car
) )
747 (when (> e
1) (setq fs-phi
(nconc fs-phi
(list `(,p
,(1- e
))))))
749 gb
(zn-primroot b phi
(mapcar #'car fs-phi
))
750 c
(mod (* (inv-mod b a
) (- 1 gb
)) a
) ;; CRT: h = gb mod b
751 h
(+ (* b c
) gb
) ;; CRT: h = 1 mod a
753 gs
(mapcar #'(lambda (g) (+ (* a
(mod (* ia
(- 1 g
)) b
)) g
)) gs
)
756 fs-ords
(cons fs-phi fs-ords
)
758 ;; lemma 3, page 101 :
760 (mapcar #'(lambda (g ord f
)
761 (mapcar #'(lambda (pe)
763 (list (power-mod g
(truncate ord
(apply #'expt pe
)) m
)) ))
766 (setq pegs
(sort (apply #'append pegs
) #'zn-pe
>))
767 (do ((todo pegs
(nreverse left
))
768 (q 0 0) (fg 1 1) (left nil nil
)
772 (setq p
(car peg
) g
(caddr peg
))
775 (setq q p fg
(mod (* fg g
) m
)) ))
779 ;; r-th roots --------------------------------------------------------------- ;;
781 ;; If the residue class a is an r-th power modulo n and contained in a multiplication
782 ;; subgroup of (Z/nZ), return all r-th roots from this subgroup and false otherwise.
784 (defmfun $zn_nth_root
(a r n
&optional fs-n
)
785 (unless (and (integerp a
) (integerp r
) (integerp n
))
786 (gf-merror (intl:gettext
787 "`zn_nth_root' needs three integer arguments. Found ~m, ~m, ~m." ) a r n
))
788 (unless (and (> r
0) (> n
0))
789 (gf-merror (intl:gettext
790 "`zn_nth_root': Second and third arg must be pos integers. Found ~m, ~m." ) r n
))
792 (if (and ($listp fs-n
) ($listp
(cadr fs-n
)))
793 (setq fs-n
(mapcar #'cdr
(cdr fs-n
))) ;; Lispify fs-n
794 (gf-merror (intl:gettext
795 "`zn_nth_root': The opt fourth arg must be of the form [[p1, e1], ..., [pk, ek]]." ))))
796 (let ((rts (zn-nrt a r n fs-n
)))
797 (when rts
(cons '(mlist simp
) rts
)) ))
799 (defun zn-nrt (a r n
&optional fs-n
)
800 (let (g n
/g c p q aq ro ord qs rt rts rems res
)
801 (unless fs-n
(setq fs-n
(let (($intfaclim
)) (get-factor-list n
))))
804 ((every #'onep
(mapcar #'second fs-n
)) ;; RSA-like case (n is squarefree)
805 (when (= a
0) (return-from zn-nrt
(list 0))) ) ;; n = 1: exit here
807 ;; Handle residue classes not coprime to n (n is not squarefree):
808 ;; Use Theorems 49 and 50 from
809 ;; Shanks - Solved and Unsolved Problems in Number Theory
810 (setq g
(gcd a n
) n
/g
(truncate n g
))
811 (when (/= (gcd g n
/g
) 1) ;; a is not contained in any mult. subgroup (Th. 50):
812 (return-from zn-nrt nil
) ) ;; exit here
813 (when (= a
0) (return-from zn-nrt
(list 0)))
814 ;; g = gcd(a,n). Now assume gcd(g,n/g) = 1.
815 ;; There are totient(n/g) multiples of g, i*g, with gcd(i,n/g) = 1,
816 ;; which form a modulo multiplication subgroup of (Z/nZ),
817 ;; isomorphic to (Z/mZ)*, where m = n/g.
818 ;; a is one of these multiples of g.
819 ;; Find the r-th roots of a resp. mod(a,m) in (Z/mZ)* and then
820 ;; by using CRT all corresponding r-th roots of a in (Z/nZ).
823 c
(inv-mod g n
/g
) ;; CRT-coeff
824 ;; isomorphic mapping (Th. 49):
825 ;; (use CRT with x = 0 mod g and x = rt mod n/g)
826 res
(mapcar #'(lambda (rt) (* g
(mod (* c rt
) n
/g
))) rts
) )
827 (return-from zn-nrt
(sort res
#'<)) ))
829 ;; for every prime power factor of n
830 ;; reduce a and r if possible and call zq-nrt:
835 ord
(* (1- p
) (truncate q p
)) )
838 (setq ro
(mod r ord
))
839 (when (= ro
0) (setq ro ord
)) )
843 (if (or (= p q
) (= ro
1))
845 (return-from zn-nrt nil
) ))
847 (setq rt
(list aq
)) )
849 (setq rt
(zq-nrt aq ro p q
))
850 (unless rt
(return-from zn-nrt nil
)) ))
853 ;; CRT in case n splits into more than one factor:
854 (if (= 1 (length fs-n
))
855 (setq res rt
) ;; n is a prime power
856 (setq qs
(nreverse qs
)
857 rems
(zn-distrib-lists (nreverse rts
))
858 res
(mapcar #'(lambda (rs) (car (chinese rs qs
))) rems
) ))
861 ;; return all possible combinations containing one entry per list:
862 ;; (zn-distrib-lists '((1 2 3) (4) (5 6)))
863 ;; --> ((1 4 5) (1 4 6) (2 4 5) (2 4 6) (3 4 5) (3 4 6))
865 (defun zn-distrib-lists (ll)
866 (let ((res (car ll
)) tmp e
)
867 (dolist (l (cdr ll
) res
)
871 (setq e
(if (listp r
) (copy-list r
) (list r
)))
872 (push (nconc e
(list n
)) tmp
) ))
873 (setq res
(nreverse tmp
)) )))
875 ;; handle composite r (which are not coprime to totient(q)):
876 ;; e.g. r=x*x*y*z, then a^(1/r) = (((a^(1/x))^(1/x))^(1/y))^(1/z)
878 (defun zq-nrt (a r p q
) ;; prime power q = p^e
879 ;; assume a < q, r <= q
882 ((or (= 1 r
) (primep r
))
883 (setq rts
(zq-amm a r p q
)) )
884 ((and (= (gcd r
(1- p
)) 1) (or (= p q
) (= (gcd r p
) 1))) ;; r is coprime to totient(q):
885 (let ((ord (* (1- p
) (truncate q p
))))
886 (setq rts
(list (power-mod a
(inv-mod r ord
) q
))) )) ;; unique solution
888 (let* (($intfaclim
) (rs (get-factor-list r
)))
889 (setq rs
(sort rs
#'< :key
#'car
))
893 #'(lambda (pe) (apply #'(lambda (p e
) (make-list e
:initial-element p
)) pe
))
895 (setq rts
(zq-amm a
(car rs
) p q
))
897 (setq rts
(apply #'nconc
(mapcar #'(lambda (a) (zq-amm a r p q
)) rts
))) ))))
898 (if (and (= p
2) (> q
2) (evenp r
)) ;; this case needs a postprocess (see below)
899 (nconc (mapcar #'(lambda (rt) (- q rt
)) rts
) rts
) ;; add negative solutions
902 ;; Computing r-th roots modulo a prime power p^n, where r is a prime
905 ;; Bach,Shallit - Algorithmic Number Theory, Theorem 7.3.2
907 ;; Shanks - Solved and Unsolved Problems in Number Theory, Th. 46, Lemma 1 to Th. 44
909 ;; The algorithm AMM (Adleman, Manders, Miller) is essentially based on
910 ;; properties of cyclic groups and with the exception of q = 2^n, n > 2
911 ;; it can be applied to any multiplicative group (Z/qZ)* where q = p^n.
913 ;; Doing so, the order q-1 of Fq* in Th. 7.3.2 has to be replaced by the
914 ;; group order totient(q) of (Z/qZ)*.
916 ;; But how to include q = 8,16,32,... ?
917 ;; r > 2: r is prime. There exists a unique solution for all a in (Z/qZ)*.
918 ;; r = 2 (the square root case):
919 ;; - (Z/qZ)* has k = 2 characteristic factors [2,q/4] with [-1,3] as possible
920 ;; factor generators (see Shanks, Lemma 1 to Th. 44).
921 ;; I.e. 3 is of order q/4 and 3^2 = 9 of order q/8.
922 ;; - (Z/qZ)* has totient/2^k = q/8 quadratic residues with 2^k = 4 roots each
923 ;; (see Shanks, Th. 46).
924 ;; - It follows that the subgroup <3> generated by 3 contains all quadratic
925 ;; residues of (Z/qZ)* (which must be all the powers of 9 located in <3>).
926 ;; - We apply the algorithm AMM for cyclic groups to <3> and compute two
928 ;; - The numbers -x and -y, obviously roots as well, both lie in (-1)*<3>
929 ;; and therefore they differ from x,y and complete the set of 4 roots.
931 (defun zq-amm (a r p q
) ;; r,p prime, q = p^n
932 ;; assume a < q, r <= q
935 ((= 2 q
) (when (= 1 a
) (list 1)))
936 ((= 4 q
) (when (or (= 1 a
) (and (= 3 a
) (oddp r
))) (list a
)))
938 (let ((ord (* (1- p
) (truncate q p
))) ;; group order: totient(q)
942 (when (/= 1 (mod a
8)) (return-from zq-amm nil
)) ;; a must be a power of 9
944 ((/= 1 ($jacobi
(mod a p
) p
))
945 (return-from zq-amm nil
) )
947 (setq rt
(power-mod a
(ash (+ ord
2) -
2) q
))
948 (return-from zq-amm
`(,rt
,(- q rt
))) )
949 ((and (= p q
) (= 5 (mod p
8)))
951 (y (power-mod x
(ash (- p
5) -
3) p
))
952 (i (mod (* x y y
) p
))
953 (rt (mod (* a y
(1- i
)) p
)) )
954 (return-from zq-amm
`(,rt
,(- p rt
))) )))))
955 (when (= 2 p
) ;; q = 8,16,32,..
956 (setq ord
(ash ord -
1)) ) ;; factor generator 3 is of order ord/2
957 (multiple-value-setq (s m
) (truncate ord r
))
958 (when (and (= 0 m
) (/= 1 (power-mod a s q
))) (return-from zq-amm nil
))
959 ;; r = 3, first 2 cases:
962 ((= 1 (setq m
(mod ord
3))) ;; unique solution
964 `(,(power-mod a
(truncate (1+ (ash ord
1)) 3) q
)) ))
965 ((= 2 m
) ;; unique solution
967 `(,(power-mod a
(truncate (1+ ord
) 3) q
)) ))))
968 ;; compute u,e with ord = u*r^e and r,u coprime:
971 (multiple-value-setq (u1 m
) (truncate u1 r
))
972 (when (/= 0 m
) (return))
973 (setq u u1 e
(1+ e
)) )
976 (setq rt
(power-mod a
(inv-mod r u
) q
)) ;; unique solution, see Bach,Shallit 7.3.1
978 (t ;; a is an r-th power
980 ;; find generator of order r^e:
981 (if (= p
2) ;; p = 2: then r = 2 (other r: e = 0)
983 (do ((n 2 ($next_prime n
)))
984 ((and (= 1 (gcd n q
)) (/= 1 (power-mod n s q
))) ;; n is no r-th power
985 (setq g
(power-mod n u q
)) )))
987 om
(power-mod g
(truncate re r
) q
) ) ;; r-th root of unity
989 ((or (/= 3 r
) (= 0 (setq m
(mod ord
9))))
990 (let (ar au br bu k ab alpha beta
)
991 ;; map a from Zq* to C_{r^e} x C_u:
992 (setq ar
(power-mod a u q
) ;; in C_{r^e}
993 au
(power-mod a re q
) ) ;; in C_u
994 ;; compute direct factors of rt:
995 ;; (the loop in algorithm AMM is effectively a Pohlig-Hellman-reduction, equivalent to zn-dlog)
996 (setq k
(zn-dlog ar g q re
`((,r
,e
))) ;; g^k = ar, where r|k
997 br
(power-mod g
(truncate k r
) q
) ;; br^r = g^k (factor of rt in C_{r^e})
998 bu
(power-mod au
(inv-mod r u
) q
) ) ;; bu^r = au (factor of rt in C_u)
999 ;; mapping from C_{r^e} x C_u back to Zq*:
1000 (setq ab
(cdr (zn-gcdex1 u re
))
1003 (if (< alpha
0) (incf alpha ord
) (incf beta ord
))
1004 (setq rt
(mod (* (power-mod br alpha q
) (power-mod bu beta q
)) q
)) ))
1005 ;; r = 3, remaining cases:
1007 (setq rt
(power-mod a
(truncate (+ (ash ord
1) 3) 9) q
)) )
1009 (setq rt
(power-mod a
(truncate (+ ord
3) 9) q
)) ))
1010 ;; mult with r-th roots of unity:
1011 (do ((i 1 (1+ i
)) (j 1) (res (list rt
)))
1013 (setq j
(mod (* j om
) q
))
1014 (push (mod (* rt j
) q
) res
) ))))))))
1016 ;; -------------------------------------------------------------------------- ;;
1019 ;; Two variants of gcdex:
1021 ;; returns gcd as first entry:
1022 ;; (zn-gcdex1 12 45) --> (3 4 -1), so 4*12 + -1*45 = 3
1023 (defun zn-gcdex1 (x y
)
1024 (let ((x1 1) (x2 0) (y1 0) (y2 1) q r
)
1025 (do ()((= 0 y
) (list x x1 x2
))
1026 (multiple-value-setq (q r
) (truncate x y
))
1028 (psetf x1 y1 y1
(- x1
(* q y1
)))
1029 (psetf x2 y2 y2
(- x2
(* q y2
))) )))
1031 ;; returns gcd as last entry:
1032 ;; (zn-gcdex 12 45 21) --> (4 -1 0 3), so 4*12 + -1*45 + 0*21 = 3
1033 (defun zn-gcdex (&rest args
)
1034 (let* ((ex (zn-gcdex1 (car args
) (cadr args
)))
1037 (dolist (a (cddr args
) (nconc cs
(list g
)))
1038 (setq ex
(zn-gcdex1 g a
)
1042 cs
(nconc (mapcar #'(lambda (c) (* c c1
)) cs
) (cdr ex
)) ))))
1045 ;; for educational puposes: tables of small residue class rings
1047 (defun zn-table-errchk (n fun
)
1048 (unless (and (fixnump n
) (< 1 n
))
1049 (gf-merror (intl:gettext
1050 "Argument to `~m' must be a small fixnum greater than 1." ) fun
)))
1052 (defmfun $zn_add_table
(n)
1053 (zn-table-errchk n
"zn_add_table")
1054 (do ((i 0 (1+ i
)) res
)
1056 (cons '($matrix simp
) (nreverse res
)) )
1057 (push (mfuncall '$makelist
`((mod) (+ ,i $j
) ,n
) '$j
0 (1- n
)) res
) ))
1059 ;; multiplication table modulo n
1061 ;; The optional g allows to choose subsets of (Z/nZ). Show i with gcd(i,n) = g resp. all i#0.
1062 ;; If n # 1 add row and column headings for better readability.
1064 (defmfun $zn_mult_table
(n &optional g
)
1065 (zn-table-errchk n
"zn_mult_table")
1066 (let ((i0 1) all header choice res
)
1068 ((not g
) (setq g
1))
1069 ((equal g
'$all
) (setq all t
))
1071 (gf-merror (intl:gettext
1072 "`zn_mult_table': The opt second arg must be `all' or a small fixnum." )))
1074 (when (= n g
) (setq i0
0))
1075 (push 1 choice
) ;; creates the headers
1079 (setq choice
(cons '(mlist simp
) (nreverse choice
))) )
1080 (when (or all
(= g
(gcd i n
))) (push i choice
)) )
1081 (when (and header
(= (length choice
) 2))
1082 (return-from $zn_mult_table
) )
1083 (dolist (i (cdr choice
))
1084 (push (mfuncall '$makelist
`((mod) (* ,i $j
) ,n
) '$j choice
) res
) )
1085 (setq res
(nreverse res
))
1086 (when header
(rplaca (cdar res
) "*"))
1087 (cons '($matrix simp
) res
) ))
1089 ;; power table modulo n
1091 ;; The optional g allows to choose subsets of (Z/nZ). Show i with gcd(i,n) = g resp. all i.
1093 (defmfun $zn_power_table
(n &optional g e
)
1094 (zn-table-errchk n
"zn_power_table")
1097 ((not g
) (setq g
1))
1098 ((equal g
'$all
) (setq all t
))
1100 (gf-merror (intl:gettext
1101 "`zn_power_table': The opt second arg must be `all' or a small fixnum." ))))
1103 ((not e
) (setq e
(zn-characteristic-factors n t
)))
1105 (gf-merror (intl:gettext
1106 "`zn_power_table': The opt third arg must be a small fixnum." ))))
1107 (do ((i 0 (1+ i
)) res
)
1109 (when res
(cons '($matrix simp
) (nreverse res
))) )
1110 (when (or all
(= g
(gcd i n
)))
1111 (push (mfuncall '$makelist
`((power-mod) ,i $j
,n
) '$j
1 e
) res
) ))))
1114 ;; $zn_invert_by_lu (m p)
1115 ;; $zn_determinant (m p)
1116 ;; see below: --> galois fields--> interfaces to linearalgebra/lu.lisp
1119 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1122 ;; -----------------------------------------------------------------------------
1123 ;; *** GALOIS FIELDS ***
1125 ;; The following is a revision and improvement of the first part of share/
1126 ;; contrib/gf/gf.mac by Alasdair McAndrew, Fabrizio Caruso and Jacopo D'Aurizio
1127 ;; released under terms of the GPLv2 in 2007.
1129 ;; I would like to thank the original authors for their contribution to Maxima
1130 ;; which allowed me to study, improve and extend the source code.
1132 ;; I would also like to thank Camm Maguire who helped me coding compiler macros
1135 ;; 2012 - 2014, Volker van Nek
1137 (declare-top (special *gf-char
* *gf-exp
* *ef-arith?
*)) ;; modulus $intfaclim see above
1139 (defvar *gf-rat-header
* nil
"header of internal CRE representation")
1141 (defvar *ef-arith?
* nil
"Should extension field arithmetic be used?")
1144 (defvar *gf-char
* 0 "characteristic p")
1145 (defvar *gf-exp
* 0 "exponent n, degree of the reduction polynomial")
1146 (defvar *gf-ord
* 0 "group order, number of units")
1147 (defvar *gf-card
* 0 "cardinality, ring order")
1148 (defvar *gf-red
* nil
"reduction polynomial")
1149 (defvar *gf-prim
* nil
"primitive element")
1150 (defvar *gf-fs-ord
* nil
"ifactors of *gf-ord*")
1151 (defvar *gf-fsx
* nil
"extended factors of *gf-ord*")
1152 (defvar *gf-fsx-base-p
* nil
"*gf-fsx* in base p")
1153 (defvar *gf-x^p-powers
* nil
"x^p^i, i=0,..,n-1")
1155 (defvar *f2-red
* 0 "reduction polynomial") ;; used by ef coeff arith over binary fields
1157 (declaim (fixnum *gf-exp
* *ef-exp
*))
1160 (defvar *ef-exp
* 0 "exponent m, degree of the reduction polynomial")
1161 (defvar *ef-ord
* 0 "group order, number of units")
1162 (defvar *ef-card
* 0 "cardinality, ring order")
1163 (defvar *ef-red
* nil
"reduction polynomial")
1164 (defvar *ef-prim
* nil
"primitive element")
1165 (defvar *ef-fs-ord
* nil
"ifactors of *ef-ord*")
1166 (defvar *ef-fsx
* nil
"extended factors of *ef-ord*")
1167 (defvar *ef-fsx-base-q
* nil
"*ef-fsx* in base q = p^n")
1168 (defvar *ef-x^q-powers
* nil
"x^q^i, i=0,..,m-1")
1170 (defvar *gf-char?
* nil
"Was the characteristic defined?")
1171 (defvar *gf-red?
* nil
"Was the reduction polynomial defined?")
1172 (defvar *gf-irred?
* nil
"Is the reduction polynomial irreducible?")
1173 (defvar *gf-data?
* nil
"gf_set_data called?")
1175 (defvar *ef-red?
* nil
"Was the reduction polynomial defined?")
1176 (defvar *ef-irred?
* nil
"Is the reduction polynomial irreducible?")
1177 (defvar *ef-data?
* nil
"ef_set_data called?")
1179 (defmvar $gf_rat nil
"Return values are rational expressions?" boolean
)
1181 (defmvar $gf_symmetric nil
"A symmetric modulus should be used?" boolean
) ;; deprecated
1182 (defmvar $gf_balanced nil
"A balanced modulus should be used?" boolean
) ;; there is ec_balanced in elliptic_curves.lisp
1184 (putprop '$gf_symmetric
'gf-balanced-info
'assign
)
1186 (defun gf-balanced-info (assign-var arg
)
1187 (declare (ignore assign-var
))
1188 (setq $gf_balanced arg
)
1189 (format t
"`gf_symmetric' is deprecated and replaced by `gf_balanced'.~%The value is bound to `gf_balanced'.") )
1190 ;; temporarily print this message
1193 (defmvar $gf_coeff_limit
256
1194 "`gf_coeff_limit' limits the coeffs when searching for irreducible and primitive polynomials." fixnum
)
1196 (putprop '$gf_coeff_limit
'gf-coeff-check
'assign
)
1198 (defun gf-coeff-check (assign-var arg
)
1199 (declare (ignore assign-var
))
1200 (unless (and (integerp arg
) (> arg
1))
1201 (gf-merror (intl:gettext
1202 "`gf_coeff_limit': Assignment ignored. Value must be an integer greater than 1.~%" ))))
1204 (defmvar $gf_cantor_zassenhaus t
"Should the Cantor-Zassenhaus algorithm be used?" boolean
)
1206 (defmvar $ef_coeff_mult nil
)
1207 (defmvar $ef_coeff_add nil
)
1208 (defmvar $ef_coeff_inv nil
)
1209 (defmvar $ef_coeff_exp nil
)
1211 (defmvar $gf_powers nil
)
1212 (defmvar $gf_logs nil
)
1213 (defmvar $gf_zech_logs nil
)
1214 (defvar *gf-powers
* nil
"alpha^i, i=0,..,ord-1 where alpha is a primitive element")
1215 (defvar *gf-logs?
* nil
"Were the power and log tables calculated?")
1218 ;; contains parts of merror.lisp/merror but avoids "To debug this ...".
1220 (defun gf-merror (sstring &rest l
)
1221 (setq $error
`((mlist) ,sstring
,@ l
))
1222 (and $errormsg
($errormsg
))
1223 (fresh-line *standard-output
*)
1224 (format t
(intl:gettext
"~& -- an error.~%"))
1225 (throw 'macsyma-quit
'maxima-error
) )
1228 (defun gf-char?
(fun)
1230 (gf-merror (intl:gettext
"`~m': The characteristic is not defined yet.") fun
) ))
1232 (defun gf-red?
(fun)
1234 (gf-merror (intl:gettext
"`~m': The reduction polynomial is not defined yet.") fun
) ))
1236 (defun gf-data?
(fun)
1238 (gf-merror (intl:gettext
"`~m': gf_set_data called?") fun
) ))
1240 (defun gf-field?
(fun)
1241 (if (and (gf-data? fun
) *gf-irred?
*) t
1242 (gf-merror (intl:gettext
"`~m': The reduction polynomial is not irreducible.") fun
) ))
1245 (defun ef-gf-field?
(fun)
1246 (if (and *gf-data?
* *gf-irred?
*) t
1247 (gf-merror (intl:gettext
"`~m': The base field is not defined yet.") fun
) ))
1249 (defun ef-red?
(fun)
1250 (if (and (ef-gf-field? fun
) *ef-red?
*) t
1251 (gf-merror (intl:gettext
"`~m': The reduction polynomial is not defined yet.") fun
) ))
1253 (defun ef-data?
(fun)
1254 (if (and (ef-gf-field? fun
) *ef-data?
*) t
1255 (gf-merror (intl:gettext
"`~m': ef_set_data called?") fun
) ))
1257 (defun ef-field?
(fun)
1258 (if (and (ef-data? fun
) *ef-irred?
*) t
1259 (gf-merror (intl:gettext
"`~m': The extension is no field.") fun
) ))
1261 ;; -----------------------------------------------------------------------------
1264 ;; basic coefficient arithmetic ------------------------------------------------
1267 ;; optimize the fixnum cases
1269 (defmacro maybe-char-is-fixnum-let
(binds &body body
)
1270 `(if (or (and (not *ef-arith?
*) (typep *gf-char
* 'fixnum
))
1271 (and *ef-arith?
* (typep *gf-card
* 'fixnum
)) )
1273 (declare (fixnum ,@(mapcar #'(lambda (x) (car x
)) binds
)))
1276 (declare (integer ,@(mapcar #'(lambda (x) (car x
)) binds
)))
1279 ;; basic coefficient functions and compiler macros
1281 ;; gf coefficient arith :
1283 ;; *ef-arith?* controls coefficient arithmetic. If *ef-arith?* is false,
1284 ;; coeffs are elements of Zp, where p is the defined characteristic *gf-char*.
1285 ;; If *ef-arith?* is true, coeffs are interpreted as the integer representation
1286 ;; of a polynomial over Zp[x] reduced by the irreducible polynomial *gf-red*.
1291 (maybe-char-is-fixnum-let ((c c
))
1293 ((= 0 c
) (gf-merror (intl:gettext
"gf coefficient inversion: Quotient by zero")))
1294 (t (inv-mod c
*gf-char
*)) )))) ; *gf-char* is prime
1296 (defun gf-cpow (c n
)
1299 (maybe-char-is-fixnum-let ((c c
))
1300 (power-mod c n
*gf-char
*) )))
1305 (maybe-char-is-fixnum-let ((c c
))
1306 (mod c
*gf-char
*) )))
1308 (defun gf-ctimes (a b
)
1311 (maybe-char-is-fixnum-let ((a a
)(b b
))
1312 (mod (* a b
) *gf-char
*) )))
1314 (defun gf-cplus-b (a b
) ;; assumes that both 0 <= a,b < *gf-char*
1316 (*ef-arith?
* (ef-cplus-b a b
))
1317 (t (maybe-char-is-fixnum-let ((a a
)(b b
))
1319 (if (< (the integer s
) *gf-char
*)
1321 (- (the integer s
) *gf-char
*) ))))))
1323 (defun gf-cminus-b (c) ;; assumes that 0 <= c < *gf-char*
1327 (*ef-arith?
* (ef-cminus-b c
))
1328 (t (maybe-char-is-fixnum-let ((c c
))
1329 (- *gf-char
* c
) ))))
1331 ;; ef coefficient arith :
1334 (declare (integer c
))
1336 ((= 0 c
) (gf-merror (intl:gettext
"ef coefficient inversion: Quotient by zero")))
1337 ($ef_coeff_inv
(mfuncall '$ef_coeff_inv c
))
1338 (*gf-logs?
* (ef-cinv-by-table c
))
1339 ((= 2 *gf-char
*) (f2-inv c
))
1340 (t (let ((*ef-arith?
*))
1341 (gf-x2n (gf-inv (gf-n2x c
) *gf-red
*)) ))))
1343 (defun ef-cpow (c n
)
1345 ($ef_coeff_exp
(mfuncall '$ef_coeff_exp c n
))
1346 (*gf-logs?
* (ef-cpow-by-table c n
))
1347 ((= 2 *gf-char
*) (f2-pow c n
))
1348 (t (let ((*ef-arith?
*))
1349 (gf-x2n (gf-pow (gf-n2x c
) n
*gf-red
*)) ))))
1352 (declare (integer c
))
1357 ((= 2 *gf-char
*) (f2-red c
))
1358 (t (let ((*ef-arith?
*))
1359 (gf-x2n (gf-nred (gf-n2x c
) *gf-red
*)) ))))
1361 (setq c
(ef-cmod (abs c
)))
1362 (let ((*ef-arith?
* t
)) (gf-ctimes (1- *gf-char
*) c
)) )))
1364 (defun ef-ctimes (a b
)
1366 ($ef_coeff_mult
(mfuncall '$ef_coeff_mult a b
))
1367 (*gf-logs?
* (ef-ctimes-by-table a b
))
1368 ((= 2 *gf-char
*) (f2-times a b
))
1369 (t (let ((*ef-arith?
*))
1370 (gf-x2n (gf-times (gf-n2x a
) (gf-n2x b
) *gf-red
*)) ))))
1372 (defun ef-cplus-b (a b
)
1374 ((= 2 *gf-char
*) (logxor a b
))
1375 ($ef_coeff_add
(mfuncall '$ef_coeff_add a b
))
1376 (*gf-logs?
* (ef-cplus-by-table a b
))
1377 (t (let ((*ef-arith?
*))
1378 (gf-x2n (gf-nplus (gf-n2x a
) (gf-n2x b
))) ))))
1380 (defun ef-cminus-b (a)
1384 ($ef_coeff_mult
(mfuncall '$ef_coeff_mult
(1- *gf-char
*) a
))
1385 (*gf-logs?
* (ef-cminus-by-table a
))
1386 (t (let ((*ef-arith?
*))
1387 (gf-x2n (gf-nminus (gf-n2x a
))) ))))
1389 ;; ef coefficient arith by lookup:
1391 (defun ef-ctimes-by-table (c d
)
1392 (declare (fixnum c d
))
1394 ((or (= 0 c
) (= 0 d
)) 0)
1395 (t (let ((cd (+ (the fixnum
(svref $gf_logs c
))
1396 (the fixnum
(svref $gf_logs d
)) )))
1397 (svref $gf_powers
(if (< (the integer cd
) *gf-ord
*) cd
(- cd
*gf-ord
*))) ))))
1399 (defun ef-cminus-by-table (c)
1400 (declare (fixnum c
))
1404 (t (let ((e (ash *gf-ord
* -
1))) (declare (fixnum e
))
1405 (setq c
(svref $gf_logs c
))
1406 (svref $gf_powers
(the fixnum
(if (< c e
) (+ c e
) (- c e
)))) ))))
1408 (defun ef-cinv-by-table (c)
1409 (declare (fixnum c
))
1411 ((= 0 c
) (gf-merror (intl:gettext
"ef coefficient inversion: Quotient by zero")))
1412 (t (svref $gf_powers
(- *gf-ord
* (the fixnum
(svref $gf_logs c
))))) ))
1414 (defun ef-cplus-by-table (c d
)
1415 (declare (fixnum c d
))
1419 (t (setq c
(svref $gf_logs c
) d
(aref $gf_logs d
))
1420 (let ((z (svref $gf_zech_logs
(the fixnum
(if (< d c
) (+ *gf-ord
* (- d c
)) (- d c
))))))
1423 (svref $gf_powers
(the fixnum
(if (> z
*gf-ord
*) (- z
*gf-ord
*) z
))) )
1426 (defun ef-cpow-by-table (c n
)
1427 (declare (fixnum c n
))
1431 (t (svref $gf_powers
1432 (mod (* n
(the fixnum
(svref $gf_logs c
))) *gf-ord
*) )) ))
1435 (defun gf-pow-by-table (x n
) ;; table lookup uses current *gf-red* for reduction
1436 (declare (fixnum n
))
1438 ((= 0 n
) (list 0 1))
1440 (t (svref *gf-powers
*
1441 (mod (* n
(the fixnum
(svref $gf_logs
(gf-x2n x
)))) *gf-ord
*) )) ))
1444 ;; ef coefficient arith for binary base fields:
1447 (declare (optimize (speed 3) (safety 0)))
1448 (let* ((red *f2-red
*)
1449 (ilen (integer-length red
))
1451 (declare (fixnum e ilen
))
1453 (setq e
(- (integer-length a
) ilen
))
1454 (when (< e
0) (return a
))
1455 (setq a
(logxor a
(ash red e
))) )))
1457 (defun f2-times (a b
)
1458 (declare (optimize (speed 3) (safety 0)))
1459 (let* ((ilen (integer-length b
))
1460 (a1 (ash a
(1- ilen
)))
1462 (do ((i (- ilen
2) (1- i
)) (k 0))
1463 ((< i
0) (f2-red ab
))
1464 (declare (fixnum i k
))
1471 (defun f2-pow (a n
) ;; assume n >= 0
1472 (declare (optimize (speed 3) (safety 0))
1479 (setq res
(if res
(f2-times a res
) a
))
1481 (return-from f2-pow res
) ))
1483 a
(f2-times a a
)) ))))
1486 (declare (optimize (speed 3) (safety 0)))
1488 (gf-merror (intl:gettext
"f2 arithmetic: Quotient by zero")) )
1489 (let ((b1 1) (a *f2-red
*) (a1 0) q r
)
1492 (multiple-value-setq (q r
) (f2-divide a b
))
1494 (psetf a1 b1 b1
(logxor (f2-times q b1
) a1
)) )))
1496 (defun f2-divide (a b
)
1497 (declare (optimize (speed 3) (safety 0)))
1500 (gf-merror (intl:gettext
"f2 arithmetic: Quotient by zero")) )
1501 ((= a
0) (values 0 0))
1503 (let ((ilen (integer-length b
))
1506 (declare (fixnum e ilen
))
1507 (do () ((= a
0) (values q
0))
1508 (setq e
(- (integer-length a
) ilen
))
1509 (when (< e
0) (return (values q a
)))
1510 (setq q
(logxor q
(ash 1 e
)))
1511 (setq a
(logxor a
(ash b e
))) )))))
1513 ;; -------------------------------------------------------------------------- ;;
1516 #-gcl
(eval-when (:compile-toplevel
:load-toplevel
:execute
)
1518 (define-compiler-macro gf-cmod
(a)
1522 ((and (typep *gf-char
* 'fixnum
) (typep ,a
'fixnum
)) ;; maybe a > *gf-char*
1523 (let ((x ,a
) (z *gf-char
*)) (declare (fixnum x z
))
1524 (the fixnum
(mod x z
)) ))
1526 (mod (the integer
,a
) *gf-char
*) )))
1528 (define-compiler-macro gf-ctimes
(a b
)
1532 ((typep *gf-char
* 'fixnum
)
1533 (let ((x ,a
) (y ,b
) (z *gf-char
*)) (declare (fixnum x y z
))
1534 (the fixnum
(mod (* x y
) z
)) ))
1536 (mod (* (the integer
,a
) (the integer
,b
)) *gf-char
*) )))
1538 (define-compiler-macro gf-cplus-b
(a b
) ;; assumes that both 0 <= a,b < *gf-char*
1541 (ef-cplus-b ,a
,b
) )
1542 ((typep *gf-char
* 'fixnum
)
1543 (let ((x ,a
) (y ,b
) (z *gf-char
*) (s 0)) (declare (fixnum x y z
) (integer s
))
1544 (setq s
(the integer
(+ x y
)))
1545 (if (< s z
) s
(- s z
)) ))
1547 (let ((x (+ (the integer
,a
) (the integer
,b
)))) (declare (integer x
))
1548 (if (< x
*gf-char
*) x
(- x
*gf-char
*)) ))))
1550 (define-compiler-macro gf-cminus-b
(a) ;; assumes that 0 <= a < *gf-char*
1555 ((typep *gf-char
* 'fixnum
)
1556 (let ((x ,a
) (z *gf-char
*)) (declare (fixnum x z
))
1557 (the fixnum
(- z x
)) ))
1559 (- *gf-char
* (the integer
,a
)) )))
1562 #+gcl
(eval-when (compile load eval
)
1564 (push '((fixnum fixnum
) fixnum
#.
(compiler::flags compiler
::rfa
)
1565 "(fixnum)(((long long)(#0))%((long long)(#1)))" )
1566 (get 'i%
'compiler
::inline-always
) )
1567 (push '((fixnum fixnum fixnum
) fixnum
#.
(compiler::flags compiler
::rfa
)
1568 "(fixnum)((((long long)(#0))*((long long)(#1)))%((long long)(#2)))" )
1569 (get '*%
'compiler
::inline-always
) )
1570 (push '((fixnum fixnum fixnum
) fixnum
#.
(compiler::flags compiler
::rfa compiler
::set
)
1571 "@02;({long long _t=((long long)(#0))+((long long)(#1)),_w=((long long)(#2));_t<_w ? (fixnum)_t : (fixnum)(_t - _w);})" )
1572 (get '+%b
'compiler
::inline-always
) )
1573 (push '((fixnum fixnum
) fixnum
#.
(compiler::flags compiler
::rfa
)
1574 "(fixnum)(((long long)(#1))-((long long)(#0)))" )
1575 (get 'neg%b
'compiler
::inline-always
) )
1577 (setf (get 'i%
'compiler
::return-type
) t
)
1578 (setf (get '*%
'compiler
::return-type
) t
)
1579 (setf (get '+%b
'compiler
::return-type
) t
)
1580 (setf (get 'neg%b
'compiler
::return-type
) t
)
1582 (si::define-compiler-macro gf-cmod
(a)
1586 ((and (typep *gf-char
* 'fixnum
) (typep ,a
'fixnum
) (plusp ,a
)) ;; maybe a > *gf-char*
1587 (let ((x ,a
) (z *gf-char
*)) (declare (fixnum x z
))
1590 (mod (the integer
,a
) *gf-char
*) )))
1592 (si::define-compiler-macro gf-ctimes
(a b
) ;; assume that 0 <= a,b :
1597 ',(if (< (integer-length most-positive-fixnum
) 32) `fixnum
`(signed-byte 32)) )
1598 (let ((x ,a
) (y ,b
) (z *gf-char
*)) (declare (fixnum x y z
))
1601 (mod (* (the integer
,a
) (the integer
,b
)) *gf-char
*) )))
1603 (si::define-compiler-macro gf-cplus-b
(a b
) ;; assume that both 0 <= a,b < *gf-char* :
1606 (ef-cplus-b ,a
,b
) )
1608 ',(if (< (integer-length most-positive-fixnum
) 63) `fixnum
`(signed-byte 63)) )
1609 (let ((x ,a
) (y ,b
) (z *gf-char
*)) (declare (fixnum x y z
))
1612 (let ((x (+ (the integer
,a
) (the integer
,b
)))) (declare (integer x
))
1613 (if (< x
*gf-char
*) x
(- x
*gf-char
*)) ))))
1615 (si::define-compiler-macro gf-cminus-b
(a) ;; assume that 0 <= a < *gf-char* :
1620 ((typep *gf-char
* 'fixnum
)
1621 (let ((x ,a
) (z *gf-char
*)) (declare (fixnum x z
))
1624 (- *gf-char
* (the integer
,a
)) )))
1627 ;; -----------------------------------------------------------------------------
1630 ;; setting the finite field and retrieving basic informations ------------------
1633 (defmfun $gf_set
(p &optional a1 a2 a3
) ;; deprecated
1634 (format t
"`gf_set' is deprecated. ~%~\
1635 The user is asked to use `gf_set_data' instead.~%" )
1637 (format t
"In future versions `gf_set_data' will only accept two arguments.~%") )
1638 ($gf_set_data p a1 a2 a3
) )
1641 (defmfun $gf_set_data
(p &optional a1 a2 a3
) ;; opt: *gf-exp*, *gf-red*, *gf-fs-ord*
1642 (declare (ignore a2 a3
)) ;; remove a2 a3 in next versions
1643 (let ((*ef-arith?
*))
1644 (unless (and (integerp p
) (primep p
))
1645 (gf-merror (intl:gettext
"`gf_set_data': Field characteristic must be a prime number.")) )
1649 (when a1
;; exponent or reduction poly
1652 (unless (and (fixnump a1
) (plusp a1
))
1653 (gf-merror (intl:gettext
"`gf_set_data': The exponent must be a positive fixnum.")) )
1654 (setq *gf-exp
* a1
) )
1656 (setq *gf-red
* (gf-p2x-red a1
"gf_set_data")
1657 *gf-exp
* (car *gf-red
*)
1658 *gf-irred?
* (gf-irr-p *gf-red
* *gf-char
* *gf-exp
*) )) ))
1660 (gf-set-rat-header) ;; CRE-headers
1662 (unless *gf-red
* ;; find irreducible reduction poly:
1663 (setq *gf-red
* (if (= 1 *gf-exp
*) (list 1 1) (gf-irr p
*gf-exp
*))
1666 (when (= *gf-char
* 2) (setq *f2-red
* (gf-x2n *gf-red
*)))
1668 (setq *gf-card
* (expt p
*gf-exp
*)) ;; cardinality #(F)
1670 (setq *gf-ord
* ;; group order #(F*)
1672 ((= 1 *gf-exp
*) (1- p
))
1673 ((not *gf-irred?
*) (gf-group-order *gf-char
* *gf-red
*))
1674 (t (1- (expt p
*gf-exp
*))) ))
1676 (fs (get-factor-list *gf-ord
*)) )
1677 (setq *gf-fs-ord
* (sort fs
#'< :key
#'car
)) ) ;; .. [pi, ei] ..
1679 (when *gf-irred?
* (gf-precomp))
1681 (setq *gf-prim
* ;; primitive element
1684 (if (= 2 *gf-char
*) (list 0 1)
1685 (list 0 (zn-primroot p
*gf-ord
* (mapcar #'car
*gf-fs-ord
*))) )) ;; .. pi .. (factors_only:true)
1687 (if *gf-irred?
* (gf-prim) '$unknown
) )))
1689 (setq *gf-char?
* t
*gf-red?
* t
*gf-data?
* t
) ;; global flags
1690 ($gf_get_data
) )) ;; data structure
1693 (defun gf-set-rat-header ()
1695 (setq *gf-rat-header
* (car ($rat
'$x
))) ))
1697 (defun gf-p2x-red (p fun
)
1698 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
1699 (let* ((modulus) (x (car (prep1 p
))))
1700 (unless (and (listp x
)
1701 (every #'numberp
(setq x
(cdr x
))) )
1702 (gf-merror (intl:gettext
"`~m': Not suitable as reduction polynomial: ~m") fun p
) )
1704 (unless (and (typep (car x
) 'fixnum
) (plusp (car x
)))
1705 (gf-merror (intl:gettext
"`~m': The exponent must be a positive fixnum.") fun
) )
1706 (unless (eql 1 (cadr x
))
1707 (gf-merror (intl:gettext
"`~m': A monic reduction polynomial is assumed.") fun
) )
1711 (defmfun $ef_set_data
(red)
1712 (ef-gf-field?
"ef_set_data")
1714 (let ((*ef-arith?
* t
))
1715 (setq *ef-red
* (gf-p2x-red red
"ef_set_data")
1716 *ef-exp
* (car *ef-red
*)
1717 *ef-card
* (expt *gf-card
* *ef-exp
*)
1718 *ef-irred?
* (gf-irr-p *ef-red
* *gf-card
* *ef-exp
*)
1719 *ef-ord
* (if *ef-irred?
*
1721 (gf-group-order *gf-card
* *ef-red
*) ))
1723 (fs (get-factor-list *ef-ord
*)) )
1724 (setq *ef-fs-ord
* (sort fs
#'< :key
#'car
)) )
1725 (when *ef-irred?
* (ef-precomp))
1728 *ef-prim
* (if (= 1 *ef-exp
*)
1729 (list 0 (let ((*ef-arith?
*)) (gf-x2n *gf-prim
*)))
1730 (if *ef-irred?
* (ef-prim) '$unknown
) )))
1734 (defstruct (gf-data (:print-function gf-data-short-print
))
1735 char exp red prim card
1736 ord fs-ord fsx fsx-base-p x^p-powers
)
1738 (defun gf-data-short-print (struct stream i
)
1739 (declare (ignore struct i
))
1740 (format stream
"Structure [GF-DATA]") ) ;; wxMaxima returns this
1741 ;; terminal should return this too
1743 ;; returns a struct containing all data necessary to use gf_set_again (see below)
1744 (defmfun $gf_get_data
()
1745 (gf-data?
"gf_get_data")
1747 :char
*gf-char
* ; characteristic
1748 :exp
*gf-exp
* ; exponent
1749 :red
*gf-red
* ; reduction
1750 :prim
*gf-prim
* ; primitive
1751 :card
*gf-card
* ; cardinality
1752 :ord
*gf-ord
* ; order
1753 :fs-ord
*gf-fs-ord
* ; factors of order
1754 :fsx
*gf-fsx
* ; extended factors of order
1755 :fsx-base-p
*gf-fsx-base-p
* ; extended factors in base p
1756 :x^p-powers
*gf-x^p-powers
* )) ; pre-calculated powers
1758 (defstruct (ef-data (:print-function ef-data-short-print
))
1760 ord fs-ord fsx fsx-base-q x^q-powers
)
1762 (defun ef-data-short-print (struct stream i
)
1763 (declare (ignore struct i
))
1764 (format stream
"Structure [EF-DATA]") )
1766 (defstruct1 '(($ef_data
)
1767 $exponent $reduction $primitive $cardinality $order $factors_of_order
))
1769 (defmfun $ef_get_data
()
1770 (ef-data?
"ef_get_data")
1772 :exp
*ef-exp
* ; exponent
1773 :red
*ef-red
* ; reduction
1774 :prim
*ef-prim
* ; primitive
1775 :card
*ef-card
* ; cardinality
1776 :ord
*ef-ord
* ; order
1777 :fs-ord
*ef-fs-ord
* ; factors of order
1778 :fsx
*ef-fsx
* ; extended factors of order
1779 :fsx-base-q
*ef-fsx-base-q
* ; extended factors in base q
1780 :x^q-powers
*ef-x^q-powers
* )) ; pre-calculated powers
1782 (defmfun $gf_info
(&optional
(t? t
))
1783 (gf-data?
"gf_info")
1784 (let ((no-prim (or (null *gf-prim
*) (equal *gf-prim
* '$unknown
)))
1787 "characteristic = ~a~:[, ~;~%~]~\
1788 reduction polynomial = ~a~:[, ~;~%~]~\
1789 primitive element = ~a~:[, ~;~%~]~\
1790 nr of elements = ~a~:[, ~;~%~]~\
1791 nr of units = ~a~:[, ~;~]~\
1792 ~:[~;~%nr of primitive elements = ~a~] ~%"
1794 (mfuncall '$string
(gf-x2p *gf-red
*)) t?
1798 (gf-x2p *gf-prim
*) )) t?
1800 *gf-ord
* (or t? no-prim
) (not no-prim
)
1801 (totient-by-fs-n *gf-fs-ord
*) )))
1803 (defun totient-by-fs-n (fs-n)
1805 (dolist (f fs-n phi
)
1806 (setq p
(car f
) e
(cadr f
))
1807 (setq phi
(* phi
(1- p
) (expt p
(1- e
)))) )))
1809 (defmfun $gf_infolist
() ;; enables testing gf_set_data in rtest
1810 (gf-data?
"gf_infolist")
1811 (let ((*ef-arith?
*))
1815 ,(if (or (null *gf-prim
*) (equal *gf-prim
* '$unknown
))
1817 (gf-x2p *gf-prim
*) )
1821 (defmfun $ef_info
(&optional
(t? t
))
1822 (ef-data?
"ef_info")
1823 (let ((no-prim (or (null *ef-prim
*) (equal *ef-prim
* '$unknown
)))
1826 "reduction polynomial = ~a~:[, ~;~%~]~\
1827 primitive element = ~a~:[, ~;~%~]~\
1828 nr of elements = ~a~:[, ~;~%~]~\
1829 nr of units = ~a~:[, ~;~]~\
1830 ~:[~;~%nr of primitive elements = ~a~] ~%"
1831 (mfuncall '$string
(gf-x2p *ef-red
*)) t?
1835 (gf-x2p *ef-prim
*) )) t?
1837 *ef-ord
* (or t? no-prim
) (not no-prim
)
1838 (totient-by-fs-n *ef-fs-ord
*) )))
1840 (defmfun $ef_infolist
() ;; enables testing ef_set_data in rtest
1841 (ef-data?
"ef_infolist")
1842 (let ((*ef-arith?
* t
))
1845 ,(if (or (null *ef-prim
*) (equal *ef-prim
* '$unknown
))
1847 (gf-x2p *ef-prim
*) )
1852 (defmfun $gf_unset
()
1853 (setq $gf_powers nil $gf_logs nil $gf_zech_logs nil
*gf-powers
* nil
*gf-logs?
* nil
1855 $ef_coeff_mult nil $ef_coeff_add nil $ef_coeff_inv nil $ef_coeff_exp nil
1856 *gf-rat-header
* nil
*gf-char
* 0
1857 *gf-exp
* 1 *gf-ord
* 0 *gf-card
* 0 ;; *gf-exp* = 1 when gf_set_data has no optional arg
1858 *gf-red
* nil
*f2-red
* 0 *gf-prim
* nil
1859 *gf-fs-ord
* nil
*gf-fsx
* nil
*gf-fsx-base-p
* nil
*gf-x^p-powers
* nil
1860 *gf-char?
* nil
*gf-red?
* nil
*gf-irred?
* nil
*gf-data?
* nil
)
1863 (defmfun $ef_unset
()
1864 (setq *ef-exp
* 0 *ef-ord
* 0 *ef-card
* 0
1865 *ef-red
* nil
*ef-prim
* nil
1866 *ef-fs-ord
* nil
*ef-fsx
* nil
*ef-fsx-base-q
* nil
*ef-x^q-powers
* nil
1867 *ef-red?
* nil
*ef-irred?
* nil
*ef-data?
* nil
)
1872 ;; Just set characteristic and reduction poly to allow basic arithmetics on the fly.
1873 (defmfun $gf_minimal_set
(p &optional
(red))
1874 (unless (and (integerp p
) (primep p
))
1875 (gf-merror (intl:gettext
"First argument to `gf_minimal_set' must be a prime number.")) )
1880 (let ((*ef-arith?
*))
1882 (setq *gf-red
* (gf-p2x-red red
"gf_minimal_set")
1884 *gf-exp
* (car *gf-red
*) ))
1885 (format nil
"characteristic = ~a, reduction polynomial = ~a"
1887 (if red
(mfuncall '$string
(gf-x2p *gf-red
*)) "false") )))
1890 (defmfun $ef_minimal_set
(red)
1891 (ef-gf-field?
"ef_minimal_set")
1893 (let ((*ef-arith?
* t
))
1895 (setq *ef-red
* (gf-p2x-red red
"ef_minimal_set")
1896 *ef-exp
* (car *ef-red
*)
1898 (format nil
"reduction polynomial = ~a"
1899 (if red
(mfuncall '$string
(gf-x2p *ef-red
*)) "false") )))
1902 (defmfun $gf_characteristic
()
1903 (gf-char?
"gf_characteristic")
1906 (defmfun $gf_exponent
()
1907 (gf-red?
"gf_exponent")
1910 (defmfun $gf_reduction
()
1911 (gf-red?
"gf_reduction")
1912 (when *gf-red
* (let ((*ef-arith?
*)) (gf-x2p *gf-red
*))) )
1914 (defmfun $gf_cardinality
()
1915 (gf-data?
"gf_cardinality")
1919 (defmfun $ef_exponent
()
1920 (ef-red?
"ef_exponent")
1923 (defmfun $ef_reduction
()
1924 (ef-red?
"ef_reduction")
1925 (when *ef-red
* (let ((*ef-arith?
* t
)) (gf-x2p *ef-red
*))) )
1927 (defmfun $ef_cardinality
()
1928 (ef-data?
"ef_cardinality")
1932 ;; Reuse data and results from a previous gf_set_data
1933 (defmfun $gf_set_again
(data)
1934 (unless (gf-data-p data
)
1935 (gf-merror (intl:gettext
1936 "Argument to `gf_set_again' must be a return value of `gf_set_data'." )))
1939 (setq *gf-char
* (gf-data-char data
)
1940 *gf-exp
* (gf-data-exp data
)
1941 *gf-red
* (gf-data-red data
)
1942 *gf-prim
* (gf-data-prim data
)
1943 *gf-card
* (gf-data-card data
)
1944 *gf-ord
* (gf-data-ord data
)
1945 *gf-fs-ord
* (gf-data-fs-ord data
)
1946 *gf-fsx
* (gf-data-fsx data
)
1947 *gf-fsx-base-p
* (gf-data-fsx-base-p data
)
1948 *gf-x^p-powers
* (gf-data-x^p-powers data
)
1949 *gf-irred?
* (= *gf-ord
* (1- *gf-card
*))
1954 (defmfun $ef_set_again
(data)
1955 (ef-gf-field?
"ef_set_again")
1956 (unless (ef-data-p data
)
1957 (gf-merror (intl:gettext
1958 "Argument to `ef_set_again' must be a return value of `ef_set_data'." )))
1960 (setq *ef-exp
* (ef-data-exp data
)
1961 *ef-red
* (ef-data-red data
)
1962 *ef-prim
* (ef-data-prim data
)
1963 *ef-card
* (ef-data-card data
)
1964 *ef-ord
* (ef-data-ord data
)
1965 *ef-fs-ord
* (ef-data-fs-ord data
)
1966 *ef-fsx
* (ef-data-fsx data
)
1967 *ef-fsx-base-q
* (ef-data-fsx-base-q data
)
1968 *ef-x^q-powers
* (ef-data-x^q-powers data
)
1969 *ef-irred?
* (= *ef-ord
* (1- *ef-card
*))
1973 ;; -----------------------------------------------------------------------------
1976 ;; lookup tables ---------------------------------------------------------------
1979 (defmfun $gf_make_arrays
()
1980 (format t
"`gf_make_arrays' is deprecated. ~%~\
1981 The user is asked to use `gf_make_logs' instead.~%" )
1984 (defmfun $gf_make_logs
() ;; also zech-logs and antilogs
1985 (gf-field?
"gf_make_logs")
1986 (let ((*ef-arith?
*)) (gf-make-logs)) )
1988 (defun gf-make-logs ()
1989 (unless (typep *gf-ord
* 'fixnum
)
1990 (gf-merror (intl:gettext
"`gf_make_logs': group order must be a fixnum.")) )
1991 (let ((x (list 0 1)) (ord *gf-ord
*) (primx *gf-prim
*) (red *gf-red
*))
1992 (declare (fixnum ord
))
1994 ;; power table of the field, where the i-th element is (the numerical
1995 ;; equivalent of) the field element e^i, where e is a primitive element
1997 (setq $gf_powers
(make-array (1+ ord
) :element-type
'integer
)
1998 *gf-powers
* (make-array (1+ ord
) :element-type
'list
:initial-element nil
) )
1999 (setf (svref $gf_powers
0) 1
2000 (svref *gf-powers
* 0) (list 0 1) )
2003 (declare (fixnum i
))
2004 (setq x
(gf-times x primx red
))
2005 (setf (svref $gf_powers i
) (gf-x2n x
)
2006 (svref *gf-powers
* i
) x
))
2008 ;; log table: the inverse lookup of the power table
2010 (setq $gf_logs
(make-array (1+ ord
) :initial-element nil
))
2013 (declare (fixnum i
))
2014 (setf (svref $gf_logs
(svref $gf_powers i
)) i
) )
2016 ;; zech-log table: lookup table for efficient addition
2018 (setq $gf_zech_logs
(make-array (1+ ord
) :initial-element nil
))
2019 (do ((i 0 (1+ i
)) (one (list 0 1)))
2021 (declare (fixnum i
))
2022 (setf (svref $gf_zech_logs i
)
2023 (svref $gf_logs
(gf-x2n (gf-plus (svref *gf-powers
* i
) one
))) ))
2026 `((mlist simp
) ,$gf_powers
,$gf_logs
,$gf_zech_logs
) ))
2028 (defun gf-clear-tables ()
2029 (setq $gf_powers nil
2034 ;; -----------------------------------------------------------------------------
2037 ;; converting to/from internal representation ----------------------------------
2039 ;; user level <---> internal
2041 ;; integer # 0 (0 integer') where integer' = mod(integer, *gf-char*)
2043 ;; x^4 + 3*x^2 + 4 (4 1 2 3 0 4)
2045 ;; This representation uses the term part of the internal CRE representation.
2046 ;; The coeffcients are exclusively positive: 1, 2, ..., (*gf-char* -1)
2047 ;; Header informations are stored in *gf-rat-header*.
2049 ;; gf_set_data(5, 4)$
2050 ;; :lisp `(,*gf-char* ,*gf-exp*)
2052 ;; p : x^4 + 3*x^2 - 1$
2054 ;; ((MRAT SIMP ($X) (X33303)) (X33303 4 1 2 3 0 -1) . 1)
2055 ;; :lisp (gf-p2x $p)
2057 ;; :lisp *gf-rat-header*
2058 ;; (MRAT SIMP ($X) (X33303))
2060 ;; Remark: I compared the timing results of the arithmetic functions using this
2061 ;; data structure to arithmetics using an array implementation and in case of
2062 ;; modulus 2 to an implementation using bit-arithmetics over integers.
2063 ;; It turns out that in all cases the timing advantages of other data structures
2064 ;; were consumed by conversions from/to the top-level.
2065 ;; So for sparse polynomials the CRE representation seems to fit best.
2069 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2070 (setq p
(car (let ((modulus)) (prep1 p
))))
2075 (t (setq p
(gf-cmod p
))
2076 (if (= p
0) nil
(list 0 p
)) )))
2078 (setq p
(gf-mod (cdr p
)))
2079 (if (typep (car p
) 'fixnum
)
2081 (gf-merror (intl:gettext
"Exponents are limited to fixnums.")) ))))
2084 ;; version of gf-p2x that doesn't apply mod reduction
2086 (defun gf-p2x-raw (p)
2087 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2088 (setq p
(car (let ((modulus)) (prep1 p
))))
2090 ((integerp p
) (if (= 0 p
) nil
(list 0 p
)))
2092 (unless (every #'numberp p
)
2093 (gf-merror (intl:gettext
"gf: polynomials must be univariate.")) )
2098 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2102 ((= 0 (the fixnum
(car x
))) (gf-cp2smod (cadr x
)))
2103 (t (gf-np2smod x
)) ))
2108 ;; depending on $gf_rat gf-x2p returns a CRE or a ratdisrepped expression
2111 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
2113 `(,*gf-rat-header
* ,x .
1)
2114 `(,*gf-rat-header
* ,(cons (caar (cdddr *gf-rat-header
*)) x
) .
1) ))
2116 (defun gf-disrep (x &optional
(var '$x
))
2117 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2119 (maybe-char-is-fixnum-let ((c 0))
2120 (do ((not-plus?
(null (cddr x
))) p
(e 0))
2121 ((null x
) (if not-plus?
(car p
) (cons '(mplus simp
) p
)))
2122 (declare (fixnum e
))
2123 (setq e
(car x
) c
(cadr x
) x
(cddr x
)
2130 (cons `((mtimes simp
) ,c
,var
) p
) ))
2132 (cons `((mexpt simp
) ,var
,e
) p
) )
2134 (cons `((mtimes simp
) ,c
((mexpt simp
) ,var
,e
)) p
) )))))))
2136 ;; -----------------------------------------------------------------------------
2139 ;; evaluation and adjustment ---------------------------------------------------
2142 ;; an arbitrary polynomial is evaluated in a given field
2144 (defmfun $gf_eval
(a)
2145 (gf-char?
"gf_eval")
2146 (let ((*ef-arith?
*)) (gf-eval a
*gf-red
* "gf_eval")) )
2148 (defmfun $ef_eval
(a)
2149 (ef-gf-field?
"ef_eval")
2150 (let ((*ef-arith?
* t
))
2151 (unless (equal a
($expand a
))
2152 (gf-merror (intl:gettext
"`ef_eval': The argument must be an expanded polynomial.")) )
2153 (gf-eval a
*ef-red
* "ef_eval") ))
2155 (defun gf-eval (a red fun
)
2156 (setq a
(let ((modulus)) (car (prep1 a
))))
2158 ((integerp a
) (gf-cmod a
))
2160 (setq a
(gf-mod (cdr a
)))
2161 (and a
(not (typep (car a
) 'fixnum
))
2162 (gf-merror (intl:gettext
"`~m': The exponent is expected to be a fixnum.") fun
) )
2163 (gf-x2p (gf-nred a red
)) )))
2166 ;; gf-mod adjusts arbitrary integer coefficients (pos, neg or unbounded)
2169 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2171 (maybe-char-is-fixnum-let ((c 0))
2172 (do ((r x
(cddr r
)) res
)
2173 ((null r
) (nreverse res
))
2174 (unless (numberp (cadr r
))
2175 (gf-merror (intl:gettext
"gf: polynomials must be univariate.")) )
2176 (setq c
(gf-cmod (cadr r
)))
2177 (unless (= c
0) (setq res
(cons c
(cons (car r
) res
)))) ))))
2179 ;; positive 2 symmetric mod:
2181 (defun gf-np2smod (x) ;; modifies x
2184 ((not $gf_balanced
) x
)
2186 (*f-np2smod x
*gf-card
* #'(lambda (c) (neg (gf-ctimes (1- *gf-char
*) c
)))) )
2188 (*f-np2smod x
*gf-char
* #'(lambda (c) (- (the integer c
) *gf-char
*))) )))
2190 (defun *f-np2smod
(x p cp2smod-fn
)
2192 (maybe-char-is-fixnum-let ((p2 (ash p -
1)))
2193 (do ((r (cdr x
) (cddr r
))) (())
2194 (when (> (the integer
(car r
)) p2
)
2195 (rplaca r
(funcall cp2smod-fn
(car r
))) )
2196 (when (null (cdr r
)) (return x
)) ))))
2198 ;; adjust a coefficient to a symmetric modulus:
2199 (defun gf-cp2smod (c)
2201 ((not $gf_balanced
) c
)
2203 (if (> c
(ash *gf-card
* -
1)) (neg (gf-ctimes c
(1- *gf-char
*))) c
) )
2205 (if (> c
(ash *gf-char
* -
1)) (- (the integer c
) *gf-char
*) c
) )))
2207 ;; -----------------------------------------------------------------------------
2210 ;; arithmetic in Galois Fields - Maxima level functions ------------------------
2215 (defmfun $gf_neg
(a)
2217 (let ((*ef-arith?
*))
2218 (gf-x2p (gf-nminus (gf-p2x a
))) ))
2220 (defmfun $gf_add
(&rest args
)
2222 (let ((*ef-arith?
*))
2223 (setq args
(mapcar #'gf-p2x args
))
2224 (gf-x2p (reduce #'gf-plus args
)) ))
2226 (defmfun $gf_sub
(&rest args
)
2228 (let ((*ef-arith?
*))
2229 (setq args
(mapcar #'gf-p2x args
))
2230 (gf-x2p (gf-plus (car args
) (gf-minus (reduce #'gf-plus
(cdr args
))))) ))
2232 (defmfun $gf_mult
(&rest args
)
2233 (gf-char?
"gf_mult")
2234 (let ((*ef-arith?
*))
2235 (setq args
(mapcar #'gf-p2x args
))
2237 (not (some #'null args
))
2238 (not (typep (apply #'+ (mapcar #'car args
)) 'fixnum
))
2239 (gf-merror (intl:gettext
"`gf_mult': Resulting exponent won't be a fixnum.")) )
2240 (gf-x2p (reduce #'(lambda (x y
) (gf-times x y
*gf-red
*)) args
)) ))
2242 (defmfun $gf_reduce
(a b
)
2243 (gf-char?
"gf_reduce")
2244 (let ((*ef-arith?
*))
2245 (gf-x2p (gf-nrem (gf-p2x a
) (gf-p2x b
))) ))
2247 (defmfun $gf_inv
(a)
2249 (let ((*ef-arith?
*))
2250 (setq a
(gf-inv (gf-p2x a
) *gf-red
*))
2251 (when a
(gf-x2p a
)) )) ;; a is nil in case the inverse does not exist
2253 (defmfun $gf_div
(&rest args
)
2256 (gf-merror (intl:gettext
"`gf_div' needs at least two arguments." )) )
2257 (let* ((*ef-arith?
*)
2258 (a2 (mapcar #'gf-p2x args
))
2259 (a2 (cons (car a2
) (mapcar #'(lambda (x) (gf-inv x
*gf-red
*)) (cdr a2
)))) )
2261 ((some #'null
(cdr a2
)) ;; but check if exact division is possible ..
2262 (let ((q (gf-p2x (car args
))) r
)
2263 (setq args
(cdr args
))
2264 (do ((d (car args
) (car args
)))
2265 ((null d
) (gf-x2p q
))
2266 (multiple-value-setq (q r
) (gf-divide q
(gf-p2x d
)))
2267 (when r
(return)) ;; .. in case it is not return false
2268 (setq args
(cdr args
)) )))
2269 (t ;; a / b = a * b^-1 :
2270 (gf-x2p (reduce #'(lambda (x y
) (gf-times x y
*gf-red
*)) a2
)) ))))
2272 (defmfun $gf_exp
(a n
)
2274 (let ((*ef-arith?
*))
2277 (gf-merror (intl:gettext
"`gf_exp' needs two arguments.")) )
2279 (gf-merror (intl:gettext
"Second argument to `gf_exp' must be an integer.")) )
2280 ((< (the integer n
) 0)
2282 (gf-merror (intl:gettext
"`gf_exp': Unknown reduction polynomial.")) )
2283 (setq a
(gf-inv (gf-p2x a
) *gf-red
*))
2284 (when a
($gf_exp
(gf-x2p a
) (neg n
))) ) ;; a is nil in case the inverse does not exist
2286 (gf-x2p (gf-pow-by-table (gf-p2x a
) n
)) )
2287 ((and *gf-irred?
* *gf-x^p-powers
*)
2288 (gf-x2p (gf-pow$
(gf-p2x a
) n
*gf-red
*)) )
2293 (not (typep (* n
(car a
)) 'fixnum
))
2294 (gf-merror (intl:gettext
"`gf_exp': Resulting exponent won't be a fixnum.")) )
2295 (gf-x2p (gf-pow a n
*gf-red
*)) ))))
2299 (defmfun $ef_neg
(a)
2300 (ef-gf-field?
"ef_neg")
2301 (let ((*ef-arith?
* t
))
2302 (gf-x2p (gf-nminus (gf-p2x a
))) ))
2304 (defmfun $ef_add
(&rest args
)
2305 (ef-gf-field?
"ef_add")
2306 (let ((*ef-arith?
* t
))
2307 (setq args
(mapcar #'gf-p2x args
))
2308 (gf-x2p (reduce #'gf-plus args
)) ))
2310 (defmfun $ef_sub
(&rest args
)
2311 (ef-gf-field?
"ef_sub")
2312 (let ((*ef-arith?
* t
))
2313 (setq args
(mapcar #'gf-p2x args
))
2314 (gf-x2p (gf-plus (car args
) (gf-minus (reduce #'gf-plus
(cdr args
))))) ))
2316 (defmfun $ef_mult
(&rest args
)
2317 (ef-gf-field?
"ef_mult")
2318 (let ((*ef-arith?
* t
)
2320 (setq args
(mapcar #'gf-p2x args
))
2322 (not (some #'null args
))
2323 (not (typep (apply #'+ (mapcar #'car args
)) 'fixnum
))
2324 (gf-merror (intl:gettext
"`ef_mult': Resulting exponent won't be a fixnum.")) )
2325 (gf-x2p (reduce #'(lambda (x y
) (gf-times x y red
)) args
)) ))
2327 (defmfun $ef_reduce
(a b
)
2328 (ef-gf-field?
"ef_reduce")
2329 (let ((*ef-arith?
* t
))
2330 (gf-x2p (gf-nrem (gf-p2x a
) (gf-p2x b
))) ))
2332 (defmfun $ef_inv
(a)
2334 (let ((*ef-arith?
* t
))
2335 (setq a
(gf-inv (gf-p2x a
) *ef-red
*))
2336 (when a
(gf-x2p a
)) ))
2338 (defmfun $ef_div
(&rest args
)
2341 (gf-merror (intl:gettext
"`ef_div' needs at least two arguments." )) )
2342 (let ((*ef-arith?
* t
)
2344 (setq args
(mapcar #'gf-p2x args
))
2346 (cons (car args
) (mapcar #'(lambda (x) (gf-inv x red
)) (cdr args
))) )
2348 ((null (car args
)) 0)
2349 ((some #'null
(cdr args
)) nil
)
2350 (t (gf-x2p (reduce #'(lambda (x y
) (gf-times x y red
)) args
))) )))
2352 (defmfun $ef_exp
(a n
)
2353 (ef-gf-field?
"ef_exp")
2354 (let ((*ef-arith?
* t
))
2356 ((< (the integer n
) 0)
2358 (gf-merror (intl:gettext
"`ef_exp': Unknown reduction polynomial.")) )
2359 (setq a
(gf-inv (gf-p2x a
) *ef-red
*))
2360 (when a
($ef_exp
(gf-x2p a
) (neg n
))) )
2361 ((and *ef-irred?
* *ef-x^q-powers
*)
2362 (gf-x2p (gf-pow$
(gf-p2x a
) n
*ef-red
*)) )
2367 (not (typep (* n
(car a
)) 'fixnum
))
2368 (gf-merror (intl:gettext
"`ef_exp': Resulting exponent won't be a fixnum.")) )
2369 (gf-x2p (gf-pow a n
*ef-red
*)) ))))
2371 ;; -----------------------------------------------------------------------------
2374 ;; arithmetic in Galois Fields - Lisp level functions --------------------------
2377 ;; Both gf (base field) and ef (extension field) Maxima level functions use
2378 ;; this Lisp level functions. The switch *ef-arith?* controls how the coefficients
2379 ;; were treated. The coefficient functions gf-ctimes and friends behave
2380 ;; differently depending on *ef-arith?*. See above definitions.
2382 ;; Remark: A prefixed character 'n' indicates a destructive function.
2386 (defun gf-xctimes (x c
)
2387 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2388 (maybe-char-is-fixnum-let ((c c
))
2389 (if (or (= 0 c
) (null x
)) nil
2390 (do* ((res (list (car x
) (gf-ctimes c
(cadr x
))))
2391 (r (cdr res
) (cddr r
))
2392 (rx (cddr x
) (cddr rx
)) )
2394 (rplacd r
(list (car rx
) (gf-ctimes c
(cadr rx
)))) ))))
2396 (defun gf-nxctimes (x c
) ;; modifies x
2397 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2398 (maybe-char-is-fixnum-let ((c c
))
2399 (if (or (= 0 c
) (null x
)) nil
2400 (do ((r (cdr x
) (cddr r
)))
2402 (rplaca r
(gf-ctimes c
(car r
))) ))))
2406 (defun gf-xectimes (x e c
)
2407 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2408 (declare (fixnum e
))
2409 (maybe-char-is-fixnum-let ((c c
))
2410 (if (or (= 0 c
) (null x
)) nil
2411 (do* ((res (list (+ e
(the fixnum
(car x
))) (gf-ctimes c
(cadr x
))))
2412 (r (cdr res
) (cddr r
))
2413 (rx (cddr x
) (cddr rx
)) )
2415 (rplacd r
(list (+ e
(the fixnum
(car rx
))) (gf-ctimes c
(cadr rx
)))) ))))
2419 (defun gf-nxetimes (x e
) ;; modifies x
2421 (do ((r x
(cddr r
)))
2423 (rplaca r
(+ e
(car r
))) )))
2428 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2429 (if (or (null x
) (= 2 *gf-char
*)) x
2430 (do* ((res (list (car x
) (gf-cminus-b (cadr x
))))
2431 (r (cdr res
) (cddr r
))
2432 (rx (cddr x
) (cddr rx
)) )
2434 (rplacd r
(list (car rx
) (gf-cminus-b (cadr rx
)))) )))
2436 (defun gf-nminus (x) ;; modifies x
2437 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2438 (if (or (null x
) (= 2 *gf-char
*)) x
2439 (do ((r (cdr x
) (cddr r
))) (())
2440 (rplaca r
(gf-cminus-b (car r
)))
2441 (when (null (cdr r
)) (return x
)) )))
2445 (defun gf-plus (x y
)
2449 (t (gf-nplus (copy-list x
) y
)) ))
2453 (defun gf-nplus (x y
) ;; modifies x
2454 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2459 (maybe-char-is-fixnum-let ((cy 0)(c 0))
2460 (prog ((ex 0)(ey 0) r
) (declare (fixnum ex ey
))
2462 (setq ex
(car x
) ey
(car y
) cy
(cadr y
))
2465 (setq x
(cons ey
(cons cy x
)) y
(cddr y
)) )
2467 (setq c
(gf-cplus-b (cadr x
) cy
) y
(cddr y
))
2470 (when (null (setq x
(cddr x
))) (return y
))
2471 (when (null y
) (return x
))
2473 (t (rplaca (cdr x
) c
)) ))
2474 (t (setq r
(cdr x
)) (go b
)) )
2477 (when (null y
) (return x
))
2478 (setq ey
(car y
) cy
(cadr y
))
2480 (while (and (cdr r
) (> (the fixnum
(cadr r
)) ey
))
2483 ((null (cdr r
)) (rplacd r y
) (return x
))
2484 ((> ey
(the fixnum
(cadr r
)))
2485 (rplacd r
(cons ey
(cons cy
(cdr r
))))
2486 (setq r
(cddr r
) y
(cddr y
)) )
2488 (setq c
(gf-cplus-b (caddr r
) cy
) y
(cddr y
))
2490 (rplacd r
(cdddr r
))
2491 (rplaca (setq r
(cddr r
)) c
) )) )
2496 (defun gf-xyecplus (x y e c
)
2499 ((null x
) (gf-xectimes y e c
))
2500 (t (gf-nxyecplus (copy-list x
) y e c
) )))
2502 ;; merge c*v^e*y into x
2504 (defun gf-nxyecplus (x y e c
) ;; modifies x
2505 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2508 ((null x
) (gf-xectimes y e c
))
2510 (maybe-char-is-fixnum-let ((cy 0) (cc 0))
2511 (prog ((e e
) (ex 0) (ey 0) r
) (declare (fixnum e ex ey
))
2513 (setq ey
(+ (the fixnum
(car y
)) e
)
2514 cy
(gf-ctimes c
(cadr y
))
2518 (setq x
(cons ey
(cons cy x
)) y
(cddr y
)) )
2520 (setq cc
(gf-cplus-b (cadr x
) cy
) y
(cddr y
))
2523 (when (null (setq x
(cddr x
))) (return (gf-xectimes y e c
)))
2524 (when (null y
) (return x
))
2526 (t (rplaca (cdr x
) cc
)) ))
2527 (t (setq r
(cdr x
)) (go b
)) )
2530 (when (null y
) (return x
))
2531 (setq ey
(+ (the fixnum
(car y
)) e
)
2532 cy
(gf-ctimes c
(cadr y
)) )
2534 (when (null (cdr r
)) (go d
))
2538 (rplacd r
(cons ey
(cons cy
(cdr r
))))
2539 (setq r
(cddr r
) y
(cddr y
))
2542 (setq cc
(gf-cplus-b (caddr r
) cy
))
2544 (rplacd r
(cdddr r
))
2545 (rplaca (setq r
(cddr r
)) cc
) )
2548 (t (setq r
(cddr r
)) (go b
)) )
2551 (setq x
(nconc x
(list (+ (the fixnum
(car y
)) e
) (gf-ctimes c
(cadr y
))))
2557 ;; For sparse polynomials (in Galois Fields) with not too high degrees
2558 ;; simple school multiplication is faster than Karatsuba.
2560 ;; x * y = (x1 + x2 + ... + xk) * (y1 + y2 + ... + yn)
2561 ;; = x1 * (y1 + y2 + ... + yn) + x2 * (y1 + y2 + ... + yn) + ...
2563 ;; where e.g. xi = ci*v^ei
2565 (defun gf-times (x y red
)
2566 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2567 (if (or (null x
) (null y
)) nil
2568 (maybe-char-is-fixnum-let ((c 0) (cx 0))
2569 (do* ((res (gf-xectimes y
(car x
) (cadr x
))) ;; x1 * (y1 + y2 + ... + yn). summands in res are sorted. res is a new list.
2570 (r1 (cdr res
)) ;; r1 marks the place of xi*y1 in res. x[i+1]*y1 will be smaller.
2571 ry
;; ry iterates over y
2572 (x (cddr x
) (cddr x
)) ;; each loop: res += xi * (y1 + y2 + ... + yn)
2574 ((or (null x
)(null y
)) (gf-nred res red
))
2575 (declare (fixnum e ex
))
2576 (setq ry y
;; start with y1 again
2577 ex
(car x
) cx
(cadr x
) ;; xi = ci*v^ei
2578 e
(+ ex
(the fixnum
(car ry
))) ;; c*v^e = xi*y1
2579 c
(gf-ctimes (cadr ry
) cx
) ) ;; zero divisor free mult in Fp^n
2581 (while (and (cdr r1
) (< e
(the fixnum
(cadr r1
))))
2582 (setq r1
(cddr r1
)) ) ;; mark the position of xi*y1
2584 (do ((r r1
)) (()) ;; merge xi*y1 into res and then xi*y2, etc...
2586 ((or (null (cdr r
)) (> e
(the fixnum
(cadr r
))))
2587 (rplacd r
(cons e
(cons c
(cdr r
))))
2589 ((= 0 (setq c
(gf-cplus-b (caddr r
) c
)))
2590 (rplacd r
(cdddr r
)) )
2591 (t (rplaca (setq r
(cddr r
)) c
)) )
2593 (when (null (setq ry
(cddr ry
))) (return))
2594 (setq e
(+ ex
(the fixnum
(car ry
)))
2595 c
(gf-ctimes (cadr ry
) cx
) )
2597 (while (and (cdr r
) (< e
(the fixnum
(cadr r
))))
2598 (setq r
(cddr r
)) ) )) )))
2602 ;; x * x = (x_1 + x_2 + ... + x_k) * (x_1 + x_2 + ... + x_k)
2604 ;; = x_1^2 + 2*x_1*x_2 + 2*x_1*x_3 + ... + x_2^2 + 2*x_2*x_3 + 2*x_2*x_4 + ...
2606 ;; = x_k^2 + x_{k-1}^2 + 2*x_{k-1}*xk + x_{k-2}^2 + 2*x_{k-2}*x_{k-1} + 2*x_{k-2}*xk + ...
2608 ;; The reverse needs some additional consing but is slightly faster.
2610 (defun gf-sq (x red
)
2611 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2614 ((and (not *ef-arith?
*) (eql *gf-char
* 2)) ;; the mod 2 case degrades to x_1^2 + x_2^2 + ... + x_k^2
2616 ((null x
) (gf-nred (nreverse res
) red
))
2617 (setq res
(cons 1 (cons (ash (car x
) 1) res
))
2620 (maybe-char-is-fixnum-let ((ci 0)(*2ci
0)(c 0))
2621 (setq x
(reverse x
)) ;; start with x_k
2622 (prog (res ;; result
2623 r
;; insertion marker in res
2624 acc
;; acc accumulates previous x_i
2625 r1
;; r1 iterates in each loop over acc
2626 (e 0) (ei 0) ) (declare (fixnum e ei
))
2628 (setq ci
(car x
) ei
(cadr x
) ;; x_i = ci*v^ei
2629 *2ci
(gf-cplus-b ci ci
) ;; 2*ci (2*ci # 0 when *gf-char* # 2)
2630 res
(cons (+ ei ei
) (cons (gf-ctimes ci ci
) res
)) ;; res += x_i^2 (ci^2 # 0, no zero divisors)
2631 r
(cdr res
) ;; place insertion marker behind x_i^2
2634 (when (or (null r1
) (= 0 *2ci
)) ;; in ef *2ci might be 0 !
2635 (when (null (setq x
(cddr x
))) (return (gf-nred res red
)))
2636 (setq acc
(cons ei
(cons ci acc
))) ;; cons previous x_i to acc ..
2637 (go a1
) ) ;; .. and start next loop
2639 (setq e
(+ ei
(the fixnum
(car r1
)))
2640 c
(gf-ctimes *2ci
(cadr r1
))
2643 (while (< e
(the fixnum
(cadr r
)))
2646 ((> e
(the fixnum
(cadr r
)))
2647 (rplacd r
(cons e
(cons c
(cdr r
))))
2650 (setq c
(gf-cplus-b c
(caddr r
)))
2652 (rplacd r
(cdddr r
))
2653 (rplaca (setq r
(cddr r
)) c
) ) ))
2658 (defun gf-pow (x n red
) ;; assume 0 <= n
2659 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2660 (declare (integer n
))
2662 ((= 0 n
) (list 0 1))
2666 (setq res
(if res
(gf-times x res red
) x
))
2668 (return-from gf-pow res
) ))
2670 x
(gf-sq x red
)) ))))
2672 ;; in a field use precomputed *gf-x^p-powers* resp. *ef-x^q-powers*
2674 (defun gf-pow$
(x n red
)
2677 (*f-pow$ x n red
*gf-card
* *ef-card
* *ef-x^q-powers
*)
2680 (*f-pow$ x n red
*gf-char
* *gf-card
* *gf-x^p-powers
*)
2681 (gf-pow x n red
) )))
2683 (defun *f-pow$
(x n red p card x^p-powers
)
2684 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2685 (declare (integer n p card
))
2687 ((= 0 n
) (list 0 1))
2689 ((>= n card
) (gf-pow x n red
))
2691 (let ((prod (list 0 1))
2693 (do (quo r
) ((= 0 n
))
2694 (multiple-value-setq (quo r
) (truncate n p
))
2697 (dolist (ni (nreverse n-base-p
))
2698 (setq y
(gf-compose (svref x^p-powers j
) x red
)
2700 prod
(gf-times prod y red
)
2705 ;; x - quotient(x, y) * y
2709 (gf-merror (intl:gettext
"~m arithmetic: Quotient by zero") (if *ef-arith?
* "ef" "gf")) )
2711 (gf-nrem (copy-list x
) y
) ))
2713 (defun gf-nrem (x y
) ;; modifies x
2714 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2716 (gf-merror (intl:gettext
"~m arithmetic: Quotient by zero") (if *ef-arith?
* "ef" "gf")) )
2718 (maybe-char-is-fixnum-let ((c 0) (lcx 0) (lcy-inv (gf-cinv (cadr y
))))
2719 (let ((e 0) (ley (car y
)))
2720 (declare (fixnum e ley
))
2721 (setq lcy-inv
(gf-cminus-b lcy-inv
))
2724 (setq e
(- (the fixnum
(car x
)) ley
))
2725 (when (< e
0) (return x
))
2727 c
(gf-ctimes lcx lcy-inv
)
2728 x
(gf-nxyecplus (cddr x
) y e c
)) )))))
2732 ;; assume lc(red) = 1, reduction poly is monic
2734 (defun gf-nred (x red
) ;; modifies x
2735 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2736 (if (or (null x
) (null red
)) x
2737 (let ((e 0) (le-red (car red
)))
2738 (declare (fixnum e le-red
))
2739 (setq red
(cddr red
))
2741 (setq e
(- (the fixnum
(car x
)) le-red
))
2742 (when (< e
0) (return x
))
2743 (setq x
(gf-nxyecplus (cddr x
) red e
(gf-cminus-b (cadr x
)))) ))))
2748 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
2754 (if (eql 0 (car x
)) (list 0 1)
2755 (gf-xctimes x
(gf-cinv (cadr x
))) ))
2756 (setq r
(gf-rem x y
))
2757 (psetf x y y r
) )))))
2759 ;; (monic) extended gcd
2761 (defun gf-gcdex (x y red
)
2762 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
2763 (let ((x1 (list 0 1)) x2 y1
(y2 (list 0 1)) q r
)
2765 (let ((inv (gf-cinv (cadr x
))))
2766 (mapcar #'(lambda (a) (gf-xctimes a inv
)) (list x1 x2 x
)) ))
2767 (multiple-value-setq (q r
) (gf-divide x y
))
2770 y1
(gf-nplus (gf-nminus (gf-times q y1 red
)) x1
)
2773 y2
(gf-nplus (gf-nminus (gf-times q y2 red
)) x2
)
2778 ;; in case the inverse does not exist it returns nil
2779 ;; (might happen when reduction poly isn't irreducible)
2781 (defun gf-inv (y red
)
2782 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2784 (gf-merror (intl:gettext
"~m arithmetic: Quotient by zero") (if *ef-arith?
* "ef" "gf")) )
2785 (let ((y1 (list 0 1)) (x red
) x1 q r
)
2786 (setq y
(copy-list y
))
2788 (when (= 0 (car x
)) ;; gcd = 1 (const)
2789 (gf-nxctimes x1
(gf-cinv (cadr x
))) ))
2790 (multiple-value-setq (q r
) (gf-divide x y
))
2794 y1
(gf-nplus (gf-nminus (gf-times q y1 red
)) x1
) )) ))
2796 ;; quotient and remainder
2798 (defun gf-divide (x y
)
2799 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2802 (gf-merror (intl:gettext
"~m arithmetic: Quotient by zero") (if *ef-arith?
* "ef" "gf")) )
2803 ((null x
) (values nil nil
))
2805 (maybe-char-is-fixnum-let ((c 0) (lcx 0) (lcyi (gf-cinv (cadr y
))))
2806 (let ((e 0) (ley (car y
)))
2807 (declare (fixnum e ley
))
2808 (setq x
(copy-list x
))
2809 (do (q (y (cddr y
)))
2810 ((null x
) (values (nreverse q
) x
))
2811 (setq e
(- (the fixnum
(car x
)) ley
))
2813 (return (values (nreverse q
) x
)) )
2816 c
(gf-ctimes lcx lcyi
) )
2817 (unless (null y
) (setq x
(gf-nxyecplus x y e
(gf-cminus-b c
))))
2818 (setq q
(cons c
(cons e q
))) ))))))
2820 ;; -----------------------------------------------------------------------------
2823 ;; polynomial/number/list - conversions ----------------------------------------
2828 (defmfun $ef_p2n
(p)
2830 (let ((*ef-arith?
* t
)) (gf-x2n (gf-p2x p
))) )
2832 (defmfun $gf_p2n
(p &optional gf-char
)
2833 (let ((*ef-arith?
*))
2836 (let ((*gf-char
* gf-char
)) (gf-x2n (gf-p2x p
))) )
2838 (gf-x2n (gf-p2x p
)) )
2840 (gf-merror (intl:gettext
"`gf_p2n': missing modulus.")) ))))
2843 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2845 (maybe-char-is-fixnum-let ((m *gf-char
*))
2846 (when *ef-arith?
* (setq m
*gf-card
*))
2850 (return (* n
(expt m
(the fixnum
(car x
)))))
2851 (setq n
(* n
(expt m
(- (the fixnum
(car x
)) (the fixnum
(caddr x
)))))) )
2852 (setq x
(cddr x
)) ))))
2856 (defun gf-n2p-errchk (fun n
)
2857 (unless (integerp n
)
2858 (gf-merror (intl:gettext
"`~m': Not an integer: ~m") fun n
) ))
2860 (defmfun $gf_n2p
(n &optional gf-char
)
2861 (gf-n2p-errchk "gf_n2p" n
)
2862 (let ((*ef-arith?
*))
2866 (let ((*gf-char
* gf-char
)) (gf-x2p (gf-n2x n
))) )
2868 (gf-x2p (gf-n2x n
)) )
2870 (gf-merror (intl:gettext
"`gf_n2p': missing modulus.")) ))))
2872 (defmfun $ef_n2p
(n)
2874 (gf-n2p-errchk "ef_n2p" n
)
2875 (let ((*ef-arith?
* t
)) (gf-x2p (gf-n2x n
))) )
2878 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2879 (declare (integer n
))
2880 (maybe-char-is-fixnum-let ((r 0) (m *gf-char
*))
2881 (let ((e 0)) (declare (fixnum e
))
2882 (when *ef-arith?
* (setq m
*gf-card
*))
2885 (multiple-value-setq (n r
) (truncate n m
))
2887 (setq x
(cons e
(cons r x
))) )
2892 (defmfun $ef_p2l
(p &optional
(len 0))
2893 (declare (fixnum len
))
2894 (let ((*ef-arith?
* t
))
2895 (cons '(mlist simp
) (gf-x2l (gf-p2x-raw p
) len
)) )) ;; more flexibility ...
2897 (defmfun $gf_p2l
(p &optional
(len 0)) ;; len = 0 : no padding
2898 (declare (fixnum len
))
2899 (let ((*ef-arith?
*))
2900 (cons '(mlist simp
) (gf-x2l (gf-p2x-raw p
) len
)) )) ;; ... by omitting mod reduction
2902 (defun gf-x2l (x len
)
2903 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
2904 (declare (fixnum len
))
2905 (do* ((e (if x
(the fixnum
(car x
)) 0))
2906 (k (max e
(1- len
)) (1- k
))
2908 ((< k
0) (nreverse l
))
2909 (declare (fixnum e k
))
2911 ((or (null x
) (> k e
))
2916 (unless (null x
) (setq e
(the fixnum
(car x
)))) ))))
2920 (defmfun $ef_l2p
(l)
2921 (gf-l2p-errchk l
"ef_l2p")
2922 (let ((*ef-arith?
* t
)) (gf-x2p (gf-l2x (cdr l
)))) )
2924 (defmfun $gf_l2p
(l)
2925 (gf-l2p-errchk l
"gf_l2p")
2926 (let ((*ef-arith?
*)) (gf-x2p (gf-l2x (cdr l
)))) )
2928 (defun gf-l2p-errchk (l fun
)
2930 (gf-merror (intl:gettext
"`~m': Argument must be a list of integers.") fun
) ))
2933 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2934 (setq l
(reverse l
))
2935 (maybe-char-is-fixnum-let ((c 0))
2936 (let ((e 0)) (declare (fixnum e
))
2939 (unless (= 0 (setq c
(car l
)))
2940 (setq x
(cons e
(cons c x
))) )
2946 (defmfun $gf_l2n
(l)
2948 (gf-l2p-errchk l
"gf_l2n")
2949 (let ((*ef-arith?
*)) (gf-l2n (cdr l
))) )
2951 (defmfun $ef_l2n
(l)
2953 (gf-l2p-errchk l
"ef_l2n")
2954 (let ((*ef-arith?
* t
)) (gf-l2n (cdr l
))) )
2957 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2958 (maybe-char-is-fixnum-let ((m *gf-char
*) (c1 (car l
)) (c 0))
2959 (when *ef-arith?
* (setq m
*gf-card
*))
2960 (setq l
(reverse (cdr l
)))
2962 ((null l
) (+ (* c1 b
) n
))
2963 (declare (integer n b
))
2964 (unless (= 0 (setq c
(car l
))) (incf n
(* c b
)))
2965 (setq b
(* b m
) l
(cdr l
)) )))
2969 (defmfun $gf_n2l
(n &optional
(len 0)) ;; in case of len = 0 the list isn't padded or truncated
2970 (declare (integer n
) (fixnum len
))
2972 (gf-n2p-errchk "gf_n2l" n
)
2974 (let ((*ef-arith?
*))
2975 (if (= 0 len
) (gf-n2l n
) (gf-n2l-twoargs n len
)) )))
2977 (defmfun $ef_n2l
(n &optional
(len 0)) ;; in case of len = 0 the list isn't padded or truncated
2978 (declare (integer n
) (fixnum len
))
2980 (gf-n2p-errchk "ef_n2l" n
)
2982 (let ((*ef-arith?
* t
))
2983 (if (= 0 len
) (gf-n2l n
) (gf-n2l-twoargs n len
)) )))
2985 (defun gf-n2l (n) ;; this version is frequently called by gf-precomp, keep it simple
2986 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2987 (declare (integer n
))
2988 (maybe-char-is-fixnum-let ((m *gf-char
*) (r 0))
2989 (when *ef-arith?
* (setq m
*gf-card
*))
2991 (multiple-value-setq (n r
) (truncate n m
))
2992 (setq l
(cons r l
)) )))
2994 (defun gf-n2l-twoargs (n len
)
2995 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2996 (declare (integer n
) (fixnum len
))
2997 (maybe-char-is-fixnum-let ((m *gf-char
*) (r 0))
2998 (when *ef-arith?
* (setq m
*gf-card
*))
2999 (do (l) ((= 0 len
) l
)
3000 (multiple-value-setq (n r
) (truncate n m
))
3004 ;; -----------------------------------------------------------------------------
3007 ;; irreducibility (Ben-Or algorithm) -------------------------------------------
3010 (defmfun $gf_irreducible_p
(a &optional p
)
3012 (p (unless (and (integerp p
) (primep p
))
3013 (gf-merror (intl:gettext
3014 "`gf_irreducible_p': Second argument must be a prime number." )) ))
3015 (t (gf-char?
"gf_irreducible_p")
3016 (setq p
*gf-char
*) ))
3017 (let* ((*ef-arith?
*)
3019 (x (gf-p2x a
)) n
) ;; gf-p2x depends on *gf-char*
3022 ((= 0 (setq n
(car x
))) nil
)
3024 (t (gf-irr-p x p
(car x
))) )))
3026 (defmfun $ef_irreducible_p
(a)
3027 (ef-gf-field?
"ef_irreducible_p")
3028 (let ((*ef-arith?
* t
))
3030 (gf-irr-p a
*gf-card
* (car a
)) ))
3032 ;; is y irreducible of degree n over Fq[x] ?
3035 (defun gf-irr-p (y q n
) ;; gf-irr-p is independent from any settings
3036 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3037 (declare (integer q
) (fixnum n
))
3038 (let* ((*gf-char
* (car (cfactorw q
)))
3040 (mx (gf-minus x
)) ;; gf-minus needs *gf-char*
3043 (setq y
(gf-xctimes y
(gf-cinv lc
))) ) ;; monicize y
3044 (do ((i 1 (1+ i
)) (xq x
) (n2 (ash n -
1)))
3046 (declare (fixnum i n2
))
3047 (setq xq
(gf-pow xq q y
))
3048 (unless (= 0 (car (gf-gcd y
(gf-plus xq mx
))))
3051 ;; find an irreducible element
3053 ;; gf_irreducible is independent from any settings
3055 (defmfun $gf_irreducible
(p n
) ;; p,n : desired characteristic and degree
3056 (unless (and (integerp p
) (primep p
) (integerp n
))
3057 (gf-merror (intl:gettext
"`gf_irreducible' needs a prime number and an integer.")) )
3059 (let* ((*gf-char
* p
)
3061 (irr (gf-irr p n
)) )
3062 (when irr
(gf-x2p irr
)) ))
3064 (defmfun $ef_irreducible
(n) ;; n : desired degree
3065 (ef-gf-field?
"ef_irreducible")
3066 (unless (integerp n
)
3067 (gf-merror (intl:gettext
"`ef_irreducible' needs an integer.")) )
3068 (let* ((*ef-arith?
* t
)
3070 (when irr
(gf-x2p irr
)) ))
3077 (*f-irr
*gf-card
* n
) )
3080 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3082 (return-from *f-irr
(list 1 1)) )
3083 (let* ((inc (min $gf_coeff_limit q
))
3084 (i-lim (expt inc n
))
3088 (gf-merror (intl:gettext
"No irreducible polynomial found.~%~\
3089 `gf_coeff_limit' might be too small.~%" )))
3090 (setq x
(let ((*gf-char
* inc
)) (gf-n2x i
)))
3091 (when (= 0 (car (last x
2)))
3092 (setq x
(cons n
(cons 1 x
)))
3093 (when (gf-irr-p x q n
) (return-from *f-irr x
)) ))))
3095 ;; -----------------------------------------------------------------------------
3098 ;; Primitive elements ----------------------------------------------------------
3101 ;; Tests if an element is primitive in the field
3103 (defmfun $gf_primitive_p
(a)
3104 (gf-data?
"gf_primitive_p") ;; --> precomputations are performed
3105 (let* ((*ef-arith?
*)
3109 ((or (= 0 n
) (>= n
*gf-card
*)) nil
)
3111 (zn-primroot-p n
*gf-char
* *gf-ord
* (mapcar #'car
*gf-fs-ord
*)) )
3115 (defmfun $ef_primitive_p
(a)
3116 (ef-data?
"ef_primitive_p") ;; --> precomputations are performed
3117 (let ((*ef-arith?
* t
))
3121 ((>= (car a
) *ef-exp
*) nil
)
3124 (let ((*ef-arith?
*)) (gf-prim-p (gf-n2x (cadr a
))))
3126 (t (ef-prim-p a
)) )))
3129 ;; Testing primitivity in (Fq^n)*:
3131 ;; We check f(x)^ei # 1 (ei = ord/pi) for all prime factors pi of ord.
3133 ;; With ei = sum(aij*q^j, j,0,m) in base q and using f(x)^q = f(x^q) we get
3135 ;; f(x)^ei = f(x)^sum(aij*q^j, j,0,m) = prod(f(x^q^j)^aij, j,0,m).
3138 ;; Special case: red is irreducible, f(x) = x+c and pi|ord and pi|q-1.
3140 ;; Then ei = (q^n-1)/(q-1) * (q-1)/pi = sum(q^j, j,0,n-1) * (q-1)/pi.
3142 ;; With ai = (q-1)/pi and using red(z) = prod(z - x^q^j, j,0,n-1) we get
3144 ;; f(x)^ei = f(x)^sum(ai*q^j, j,0,n-1) = (prod(f(x)^q^j, j,0,n-1))^ai
3146 ;; = (prod(x^q^j + c, j,0,n-1))^ai = ((-1)^n * prod(-c - x^q^j, j,0,n-1))^ai
3148 ;; = ((-1)^n * red(-c))^ai
3151 (defun gf-prim-p (x)
3154 (*f-prim-p-2 x
*gf-char
* *gf-red
* *gf-fsx
* *gf-fsx-base-p
* *gf-x^p-powers
*) )
3155 ((gf-unit-p x
*gf-red
*)
3156 (*f-prim-p-1 x
*gf-red
* *gf-ord
* *gf-fs-ord
*) )
3159 (defun ef-prim-p (x)
3162 (*f-prim-p-2 x
*gf-card
* *ef-red
* *ef-fsx
* *ef-fsx-base-q
* *ef-x^q-powers
*) )
3163 ((gf-unit-p x
*ef-red
*)
3164 (*f-prim-p-1 x
*ef-red
* *ef-ord
* *ef-fs-ord
*) )
3169 (defun *f-prim-p-1
(x red ord fs-ord
)
3170 (dolist (pe fs-ord t
)
3171 (when (equal '(0 1) (gf-pow x
(truncate ord
(car pe
)) red
)) (return)) ))
3173 ;; *f-prim-p-2 uses precomputations and exponentiation by composition
3175 (defun *f-prim-p-2
(x q red fs fs-base-q x^q-powers
)
3176 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3177 (unless (or (= 2 *gf-char
*) (= -
1 (gf-jacobi x red q
))) ;; red is assumed to be irreducible
3178 (return-from *f-prim-p-2
) )
3179 (let ((exponent (car red
))
3180 (x+c?
(and (= (car x
) 1) (= (cadr x
) 1)))
3182 (do ((i 0 (1+ i
)) (j 0 0) (lf (array-dimension fs
0)))
3184 (declare (fixnum i j lf
))
3186 ((and x
+c?
(cadr (svref fs i
))) ;; linear and pi|ord and pi|p-1
3187 (setq -c
(if (= 2 (length x
)) 0 (gf-cminus-b (car (last x
))))
3188 z
(list 0 (gf-at red -c
)) )
3189 (when (oddp exponent
) (setq z
(gf-minus z
))) ;; (-1)^n * red(-c)
3190 (setq z
(gf-pow z
(caddr (svref fs i
)) red
)) ;; ((-1)^n * red(-c))^ai
3191 (when (or (null z
) (equal z
'(0 1)))
3194 (setq prod
(list 0 1))
3195 (dolist (aij (svref fs-base-q i
))
3196 (setq y
(gf-compose (svref x^q-powers j
) x red
) ;; f(x^q^j)
3197 y
(gf-pow y aij red
) ;; f(x^q^j)^aij
3198 prod
(gf-times prod y red
)
3200 (when (or (null prod
) (equal prod
'(0 1))) ;; prod(f(x^q^j)^aij, j,0,m)
3201 (return nil
) )) ))))
3204 ;; generalized Jacobi-symbol (Bach-Shallit, Theorem 6.7.1)
3206 (defmfun $gf_jacobi
(a b
)
3207 (gf-char?
"gf_jacobi")
3208 (let* ((*ef-arith?
*)
3212 (if (null (gf-rem x y
)) 0 1)
3213 (gf-jacobi x y
*gf-char
*) )))
3215 (defmfun $ef_jacobi
(a b
)
3216 (ef-gf-field?
"ef_jacobi")
3217 (let* ((*ef-arith?
* t
)
3220 (if (= 2 (car (cfactorw *gf-card
*)))
3221 (if (null (gf-rem x y
)) 0 1)
3222 (gf-jacobi x y
*gf-card
*) )))
3224 (defun gf-jacobi (u v q
)
3225 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3226 (if (null (setq u
(gf-rem u v
))) 0
3228 (s (if (evenp (car v
)) 1 (gf-cjacobi c
))) )
3232 (setq u
(gf-xctimes u
(gf-cinv c
)))
3233 (when (every #'oddp
(list (ash (1- q
) -
1) (car u
) (car v
)))
3235 (* s
(gf-jacobi v u q
)) )))))
3237 (defun gf-cjacobi (c)
3239 (let ((*ef-arith?
*)) (gf-jacobi (gf-n2x c
) *gf-red
* *gf-char
*))
3240 ($jacobi c
*gf-char
*) ))
3243 ;; modular composition (uses Horner and square and multiply)
3246 (defmfun $gf_compose
(a b
)
3247 (gf-red?
"gf_compose")
3248 (let ((*ef-arith?
*))
3249 (gf-x2p (gf-compose (gf-p2x a
) (gf-p2x b
) *gf-red
*)) ))
3251 (defmfun $ef_compose
(a b
)
3252 (ef-red?
"ef_compose")
3253 (let ((*ef-arith?
* t
))
3254 (gf-x2p (gf-compose (gf-p2x a
) (gf-p2x b
) *ef-red
*)) ))
3256 (defun gf-compose (x y red
)
3257 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3259 ((or (null x
) (null y
)) nil
)
3262 (let ((n (gf-at y
(cadr x
))))
3263 (if (= 0 n
) nil
(list 0 n
)) ))
3266 (setq res
(gf-nplus res
(list 0 (cadr y
))))
3267 (when (null (cddr y
))
3268 (return (gf-times res
(gf-pow x
(car y
) red
) red
)) )
3269 (setq res
(gf-times res
(gf-pow x
(- (car y
) (caddr y
)) red
) red
)
3272 ;; a(n) with poly a and integer n
3274 (defun gf-at-errchk (n fun
)
3275 (unless (integerp n
)
3276 (gf-merror (intl:gettext
"`~m': Second argument must be an integer.") fun
) ))
3278 (defmfun $gf_at
(a n
) ;; integer n
3280 (gf-at-errchk n
"gf_at")
3281 (let ((*ef-arith?
*))
3282 (gf-at (gf-p2x a
) n
) ))
3284 (defmfun $ef_at
(a n
) ;; poly a, integer n
3285 (ef-gf-field?
"ef_at")
3286 (gf-at-errchk n
"ef_at")
3287 (let ((*ef-arith?
* t
))
3288 (gf-at (gf-p2x a
) n
) ))
3290 (defun gf-at (x n
) ;; Horner and square and multiply
3291 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3292 (if (or (null x
) (integerp x
)) x
3293 (maybe-char-is-fixnum-let ((n n
))
3295 (setq i
(gf-cplus-b i
(cadr x
)))
3296 (when (null (cddr x
))
3297 (setq i1
(gf-cpow n
(the fixnum
(car x
))))
3298 (return (gf-ctimes i i1
)) )
3299 (setq i1
(gf-cpow n
(- (the fixnum
(car x
)) (the fixnum
(caddr x
))))
3303 ;; find a primitive element:
3305 (defmfun $gf_primitive
()
3306 (gf-data?
"gf_primitive")
3307 (let ((*ef-arith?
*))
3309 ((null *gf-prim
*) nil
)
3310 ((equal *gf-prim
* '$unknown
)
3311 (setq *gf-prim
* (gf-prim))
3312 (unless (null *gf-prim
*) (gf-x2p *gf-prim
*)) )
3313 (t (gf-x2p *gf-prim
*)) )))
3315 (defmfun $ef_primitive
()
3316 (ef-data?
"ef_primitive")
3317 (let ((*ef-arith?
* t
))
3319 ((null *ef-prim
*) nil
)
3320 ((equal *ef-prim
* '$unknown
)
3323 (setq *ef-prim
* (let ((*ef-arith?
*)) (gf-x2n *gf-prim
*))) )
3325 (setq *ef-prim
* (ef-prim))
3326 (unless (null *ef-prim
*) (gf-x2p *ef-prim
*)) )))
3327 (t (gf-x2p *ef-prim
*)) )))
3331 (*f-prim
*gf-char
* *gf-exp
* #'gf-prim-p
) )
3334 (*f-prim
*gf-card
* *ef-exp
* #'ef-prim-p
) )
3336 (defun *f-prim
(inc e prim-p-fn
)
3337 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3338 (setq inc
(min $gf_coeff_limit inc
))
3340 (n-lim (expt inc e
))
3343 (when (= $gf_coeff_limit inc
) '$unknown
) )
3344 (setq x
(let ((*gf-char
* inc
)) (gf-n2x n
)))
3347 (setq n
(1- (* (ash n -
1) inc
))) ) ;; go to next monic poly
3348 ((funcall prim-p-fn x
)
3352 ;; precomputation for *f-prim-p:
3354 (defun gf-precomp ()
3355 (*f-precomp
(1- *gf-char
*) *gf-ord
* *gf-fs-ord
*) )
3357 (defun ef-precomp ()
3358 (*f-precomp
(1- *gf-card
*) *ef-ord
* *ef-fs-ord
*) )
3360 (defun *f-precomp
(q-1 ord fs-ord
)
3361 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3366 (sort (get-factor-list q-1
) #'< :key
#'car
) ) ;; .. [pi, ei] ..
3368 (setq fs-ord
(remove-if #'(lambda (sj) (= (car fj
) (car sj
))) fs-ord
:count
1)) )
3370 (mapcar #'(lambda (pe) (list (car pe
) t
(truncate q-1
(car pe
)))) fs-q-1
) );; .. [pi, true, (p-1)/pi] ..
3372 (mapcar #'(lambda (pe) (list (car pe
) nil
)) fs-ord
) ) ;; .. [pi, false] ..
3374 (merge 'list fs-q-1 fs-ord
#'(lambda (a b
) (< (car a
) (car b
)))) )
3377 (setq *ef-fsx
* (apply #'vector fs-list
))
3378 (setq *ef-fsx-base-q
*
3380 (mapcar #'(lambda (pe) (nreverse (gf-n2l (truncate ord
(car pe
))))) ;; qi = ord/pi = sum(aij*p^j, j,0,m)
3382 (setq *ef-x^q-powers
* (gf-x^p-powers
*gf-card
* *ef-exp
* *ef-red
*)) ) ;; x^p^j
3384 (setq *gf-fsx
* (apply #'vector fs-list
))
3385 (setq *gf-fsx-base-p
*
3387 (mapcar #'(lambda (pe) (nreverse (gf-n2l (truncate ord
(car pe
))))) ;; qi = ord/pi = sum(aij*p^j, j,0,m)
3389 (setq *gf-x^p-powers
* (gf-x^p-powers
*gf-char
* *gf-exp
* *gf-red
*)) )))) ;; x^p^j
3391 ;; returns an array of polynomials x^p^j, j = 0, 1, .. , (n-1), where n = *gf-exp*
3393 (defun gf-x^p-powers
(q n red
)
3394 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3395 (declare (integer q
) (fixnum n
))
3396 (let ((a (make-array n
:element-type
'list
:initial-element nil
)) )
3397 (setf (svref a
0) (list 1 1)) ;; x
3400 (declare (fixnum j
))
3401 (setf (svref a j
) (gf-pow (svref a
(1- j
)) q red
)) )))
3403 ;; -----------------------------------------------------------------------------
3406 ;; Primitive polynomials -------------------------------------------------------
3409 ;; test if a is a primitive polynomial over Fq
3411 (defmfun $gf_primitive_poly_p
(a &optional p
)
3413 (p (unless (and (integerp p
) (primep p
))
3414 (gf-merror (intl:gettext
"`gf_primitive_poly_p': ~m is not a prime number.") p
) ))
3415 (t (gf-char?
"gf_primitive_poly_p")
3416 (setq p
*gf-char
*) ))
3417 (let* ((*ef-arith?
*)
3419 (y (gf-p2x a
)) ;; gf-p2x depends on *gf-char*
3421 (gf-primpoly-p y p n
) ))
3423 (defmfun $ef_primitive_poly_p
(y)
3424 (ef-gf-field?
"ef_primitive_poly_p")
3425 (let ((*ef-arith?
* t
))
3427 (gf-primpoly-p y
*gf-card
* (car y
)) ))
3431 ;; TOM HANSEN AND GARY L. MULLEN
3432 ;; PRIMITIVE POLYNOMIALS OVER FINITE FIELDS
3433 ;; (gf-primpoly-p performs a full irreducibility check
3434 ;; and therefore doesn't check whether x^((q^n-1)/(q-1)) = (-1)^n * y(0) mod y)
3436 (defun gf-primpoly-p (y q n
)
3437 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3438 (declare (fixnum n
))
3439 (unless (= 1 (cadr y
)) ;; monic poly assumed
3440 (return-from gf-primpoly-p
) )
3441 (prog* ((fs-q (cfactorw q
))
3442 (*gf-char
* (car fs-q
))
3443 (*gf-exp
* (if *ef-arith?
* (cadr fs-q
) n
))
3447 ;; the constant part ...
3448 (unless (= 0 (car const
)) (return nil
))
3449 (setq const
(cadr const
))
3450 (when (oddp n
) (setq const
(gf-cminus-b const
))) ;; (-1)^n*const
3451 ;; ... must be primitive in Fq:
3452 (unless (if (and *ef-arith?
* (> *gf-exp
* 1))
3453 (let ((*ef-arith?
*)) (gf-prim-p (gf-n2x const
)))
3455 (setq fs-q-1
(sort (mapcar #'car
(get-factor-list q-1
)) #'<))
3456 (zn-primroot-p const q q-1 fs-q-1
) ))
3459 (when (= n
1) (return t
))
3460 ;; y must be irreducible:
3461 (unless (gf-irr-p y q n
) (return nil
))
3462 ;; check for all prime factors fi of r = (q^n-1)/(q-1) which do not divide q-1
3463 ;; that x^(r/fi) mod y is not an integer:
3464 (let (x^q-powers r fs-r fs-r-base-q
)
3466 (setq x^q-powers
(gf-x^p-powers q n y
)
3467 r
(truncate (1- (expt q n
)) q-1
)
3468 fs-r
(sort (mapcar #'car
(get-factor-list r
)) #'<) )
3470 (setq fs-q-1
(sort (mapcar #'car
(get-factor-list q-1
)) #'<)) )
3472 (setq fs-r
(delete-if #'(lambda (sj) (= fj sj
)) fs-r
:count
1)) )
3474 (let ((*gf-char
* q
))
3476 (mapcar #'(lambda (f) (nreverse (gf-n2l (truncate r f
)))) fs-r
) )))
3478 (return (gf-primpoly-p-exit y fs-r-base-q x^q-powers
)) )))
3480 ;; uses exponentiation by pre-computation
3481 (defun gf-primpoly-p-exit (y fs-r-base-q x^q-powers
)
3482 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3483 (do ((i 0 (1+ i
)) (j 0 0) (dim (array-dimension fs-r-base-q
0)) z zz
)
3485 (declare (fixnum i j dim
))
3486 (setq zz
(list 0 1))
3487 (dolist (aij (svref fs-r-base-q i
)) ;; fi = sum(aij*q^j, j,0,n-1)
3488 (setq z
(gf-pow (svref x^q-powers j
) aij y
)
3489 zz
(gf-times zz z y
)
3491 (when (= 0 (car zz
)) (return nil
)) ))
3494 ;; find a primitive polynomial
3496 (defmfun $gf_primitive_poly
(p n
)
3497 (unless (and (integerp p
) (primep p
) (integerp n
))
3498 (gf-merror (intl:gettext
"`gf_primitive_poly' needs a prime number and an integer.")) )
3500 (let ((*ef-arith?
*) (*gf-char
* p
)) ;; gf-x2p needs *gf-char*
3501 (gf-x2p (gf-primpoly p n
)) ))
3503 (defmfun $ef_primitive_poly
(n)
3504 (ef-gf-field?
"ef_primitive_poly")
3505 (let ((*ef-arith?
* t
))
3506 (gf-x2p (gf-primpoly *gf-card
* n
)) ))
3509 (defun gf-primpoly (q n
)
3510 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3511 (declare (fixnum n
))
3512 (let* ((fs-q (cfactorw q
))
3513 (*gf-char
* (car fs-q
))
3514 (*gf-exp
* (if *ef-arith?
* (cadr fs-q
) n
))
3517 (fs-q-1 (sort (mapcar #'car
(get-factor-list q-1
)) #'<))
3518 r fs-r fs-r-base-q
)
3521 (let ((prt (if (= q
2) 1 (zn-primroot q q-1 fs-q-1
))))
3522 (return-from gf-primpoly
3523 (list 1 1 0 (gf-cminus-b prt
)) )))
3524 ;; pre-computation part 1:
3525 (setq r
(truncate (1- (expt q n
)) q-1
)
3526 fs-r
(sort (mapcar #'car
(get-factor-list r
)) #'<) )
3528 (setq fs-r
(delete-if #'(lambda (sj) (= fj sj
)) fs-r
:count
1)) )
3530 (let ((*gf-char
* q
))
3532 (mapcar #'(lambda (f) (nreverse (gf-n2l (truncate r f
)))) fs-r
) )))
3534 (let* ((inc (min $gf_coeff_limit q
))
3535 (i-lim (expt inc n
))
3537 (do ((i (1+ inc
) (1+ i
)))
3539 (gf-merror (intl:gettext
"No primitive polynomial found.~%~\
3540 `gf_coeff_limit' might be too small.~%" )) )
3541 (setq x
(let ((*gf-char
* inc
)) (gf-n2x i
))
3542 x
(cons n
(cons 1 x
)) )
3543 (when (gf-primpoly-p2 x
*gf-char
* *gf-exp
* q n fs-q-1 fs-r-base-q
)
3546 (defun gf-primpoly-p2 (y p e q n fs-q-1 fs-r-base-q
)
3547 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3548 (declare (fixnum e n
))
3549 (when (= 1 (cadr y
)) ;; monic poly assumed
3550 (prog* ((*gf-char
* p
) (*gf-exp
* e
) (q-1 (1- q
))
3551 (const (last y
2)) )
3552 ;; the constant part ...
3553 (unless (= 0 (car const
)) (return nil
))
3554 (setq const
(cadr const
))
3555 (when (oddp n
) (setq const
(gf-cminus-b const
))) ;; (-1)^n*const
3556 ;; ... must be primitive in Fq:
3557 (unless (if (and *ef-arith?
* (> *gf-exp
* 1))
3558 (let ((*ef-arith?
*)) (gf-prim-p (gf-n2x const
)))
3559 (zn-primroot-p const q q-1 fs-q-1
) )
3561 ;; y must be irreducible:
3562 (unless (gf-irr-p y q n
) (return nil
))
3563 ;; y dependend pre-computation and final check:
3564 (return (gf-primpoly-p-exit y fs-r-base-q
(gf-x^p-powers q n y
))) )))
3566 ;; -----------------------------------------------------------------------------
3569 ;; random elements -------------------------------------------------------------
3572 ;; Produces a random element within the given environment
3574 (defmfun $gf_random
(&optional p n
)
3575 (let ((*ef-arith?
* t
))
3577 (n (let ((*gf-char
* p
))
3578 (unless *gf-red?
* (gf-set-rat-header))
3579 (gf-x2p (gf-random p n
)) ))
3580 (t (gf-data?
"gf_random")
3581 (gf-x2p (gf-random *gf-char
* *gf-exp
*)) ))))
3583 (defmfun $ef_random
(&optional q n
)
3584 (let ((*ef-arith?
* t
))
3586 (n (let ((*gf-char
* q
)) (gf-x2p (gf-random q n
))))
3587 (t (ef-data?
"ef_random")
3588 (gf-x2p (gf-random *gf-card
* *ef-exp
*)) ))))
3590 (defun gf-random (q n
)
3591 (do ((e 0 (1+ e
)) c x
)
3595 (setq x
(cons e
(cons c x
))) )))
3597 ;; -----------------------------------------------------------------------------
3600 ;; factoring -------------------------------------------------------------------
3603 (defmfun $gf_factor
(a &optional p
) ;; set p to switch to another modulus
3605 (p (unless (and (integerp p
) (primep p
))
3606 (gf-merror (intl:gettext
"`gf_factor': Second argument must be a prime number.")) )
3607 (gf-set-rat-header) )
3608 (t (gf-char?
"gf_factor")
3609 (setq p
*gf-char
*) ))
3610 (let* ((*gf-char
* p
)
3611 (modulus p
) (a ($rat a
))
3613 (when (> (length (caddar a
)) 1)
3614 (gf-merror (intl:gettext
"`gf_factor': Polynomial must be univariate.")) )
3617 ((integerp a
) (mod a
*gf-char
*))
3619 (if $gf_cantor_zassenhaus
3620 (gf-factor (gf-mod (cdr a
)) p
)
3621 (gf-ns2pmod-factors (pfactor a
)) ))
3622 (setq a
(gf-disrep-factors a
))
3623 (and (consp a
) (consp (car a
)) (equal (caar a
) 'mtimes
)
3624 (setq a
(simplifya (cons '(mtimes) (cdr a
)) nil
)) )
3627 ;; adjust results from rat3d/pfactor to a positive modulus if $gf_balanced = false
3628 (defun gf-ns2pmod-factors (fs) ;; modifies fs
3630 (maybe-char-is-fixnum-let ((m *gf-char
*))
3631 (do ((r fs
(cddr r
)))
3633 (if (integerp (car r
))
3634 (when (< (the integer
(car r
)) 0)
3635 (incf (car r
) m
) ) ;; only in the case *ef-arith?* = false
3636 (rplaca r
(gf-ns2pmod-factor (cdar r
) m
)) )))))
3638 (defun gf-ns2pmod-factor (fac m
)
3639 (do ((r (cdr fac
) (cddr r
))) (())
3640 (when (< (the integer
(car r
)) 0)
3642 (when (null (cdr r
)) (return fac
)) ))
3644 (defun gf-disrep-factors (fs)
3646 ((integerp fs
) (gf-cp2smod fs
))
3648 (setq fs
(nreverse fs
))
3650 ((null fs
) (cons '(mtimes simp factored
) p
))
3651 (declare (fixnum e
))
3652 (setq e
(the fixnum
(car fs
))
3656 ((integerp fac
) (cons (gf-cp2smod fac
) p
))
3657 ((= 1 e
) (cons (gf-disrep (gf-np2smod fac
)) p
))
3658 (t (cons `((mexpt simp
) ,(gf-disrep (gf-np2smod fac
)) ,e
) p
)) ))))))
3660 (defmfun $ef_factor
(a)
3661 (ef-gf-field?
"ef_factor")
3662 (let ((*ef-arith?
* t
))
3663 (setq a
(let ((modulus)) ($rat a
)))
3664 (when (> (length (caddar a
)) 1)
3665 (gf-merror (intl:gettext
"`ef_factor': Polynomial must be univariate.")) )
3668 ((integerp a
) (ef-cmod a
))
3671 (gf-factor (gf-mod (cdr a
)) *gf-card
*) ))
3672 (and (consp a
) (consp (car a
)) (equal (caar a
) 'mtimes
)
3673 (setq a
(simplifya (cons '(mtimes) (cdr a
)) nil
)) )
3676 (defun gf-factor (x q
) ;; non-integer x
3677 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3678 (let ((lc (cadr x
)) z
)
3680 (setq x
(gf-xctimes x
(gf-cinv lc
))) ) ;; monicize x
3681 (if (gf-irr-p x q
(car x
))
3683 (let ((sqfr (gf-square-free x
)) e y
)
3687 y
(gf-distinct-degree-factors y q
) )
3689 (setq z
(nconc (gf-equal-degree-factors w q e
) z
)) ))))
3690 (if (= 1 lc
) z
(cons lc
(cons 1 z
))) ))
3693 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3695 (maybe-char-is-fixnum-let ((m *gf-char
*))
3696 (do ((rx x
(cddr rx
)) res c
)
3697 ((or (null rx
) (= 0 (car rx
))) (nreverse res
))
3698 (setq c
(gf-ctimes (mod (the fixnum
(car rx
)) m
) (cadr rx
)))
3700 (push (1- (car rx
)) res
)
3704 (defun ef-pth-croot (c)
3705 (let ((p *gf-char
*) (*ef-arith?
* t
))
3706 (dotimes (i (1- *gf-exp
*) c
)
3707 (setq c
(gf-cpow c p
)) )))
3709 (defun gf-pth-root (x)
3710 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3711 (maybe-char-is-fixnum-let ((p *gf-char
*))
3713 (do ((rx x
(cddr rx
)) res c
)
3714 ((null rx
) (nreverse res
))
3715 (push (truncate (the fixnum
(car rx
)) p
) res
)
3717 (when *ef-arith?
* ;; p # q
3718 (setq c
(ef-pth-croot c
)) )
3721 (defun gf-gcd-cofactors (x dx
)
3722 (let ((g (gf-gcd x dx
)))
3723 (values g
(gf-divide x g
) (gf-divide dx g
)) ))
3725 (defun gf-square-free (x) ;; monic x
3726 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3727 (let (f fs
(r (gf-diff x
)) g
)
3729 ((equal '(0 1) (setq g
(gf-gcd x r
))) `((1 ,x
)))
3732 (setq r
(gf-divide x g
)
3736 (declare (fixnum m
))
3737 (multiple-value-setq (r f x
) (gf-gcd-cofactors r x
))
3738 (unless (equal '(0 1) f
)
3739 (push (list m f
) fs
) )))
3740 (unless (equal '(0 1) x
)
3742 (append (mapcar #'(lambda (v) (rplaca v
(* (car v
) *gf-char
*)))
3743 (gf-square-free (gf-pth-root x
)) )
3747 (defun gf-distinct-degree-factors (x q
)
3748 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3749 (let ((w '(1 1)) f fs
(*gf-char
* (car (cfactorw q
))) )
3751 ((equal '(0 1) x
) fs
)
3752 (declare (fixnum n
))
3753 (when (> (ash n
1) (car x
))
3754 (setq fs
(cons (list x
(car x
)) fs
))
3756 (setq w
(gf-nred w x
)
3758 f
(gf-gcd (gf-plus w
(gf-nminus (list 1 1))) x
) )
3759 (unless (equal '(0 1) f
)
3760 (setq fs
(cons (list f n
) fs
)
3761 x
(gf-divide x f
) )))
3764 (defun gf-nonconst-random (q q^n
)
3766 (setq r
(random q^n
))
3767 (when (>= r q
) (return (let ((*gf-char
* q
)) (gf-n2x r
)))) ))
3769 ;; computes Tm(x) = x^2^(m-1) + x^2^(m-2) + .. + x^4 + x^2 + x in F2[x]
3771 (defun gf-trace-poly-f2 (x m red
) ;; m > 0
3772 (let ((tm (gf-nred x red
)))
3775 (declare (fixnum i
))
3776 (setq x
(gf-sq x red
)
3777 tm
(gf-plus tm x
) ))))
3779 ;; Cantor and Zassenhaus' algorithm
3781 (defun gf-equal-degree-factors (x-and-d q mult
)
3782 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3783 (let* ((x (car x-and-d
)) (d (cadr x-and-d
))
3785 (declare (fixnum d n
))
3787 ((= n d
) (list x mult
))
3789 (let* ((p^k
(cfactorw q
)) (p (car p^k
)) (k (cadr p^k
)) (*gf-char
* p
)
3790 (f '(0 1)) (q^n
(expt q n
)) m e r r^e
)
3792 (setq m
(* k d
)) ;; q = 2^k
3793 (setq e
(ash (1- (expt q d
)) -
1)) )
3795 (do () ((and (not (equal '(0 1) f
)) (not (equal x f
))))
3796 (setq r
(gf-nonconst-random q q^n
)
3798 (when (equal '(0 1) f
)
3800 (if (= 2 p
) (gf-trace-poly-f2 r m x
) ;; q = 2^k
3801 (gf-pow r e x
) )) ;; q is odd prime power
3802 (setq f
(gf-gcd x
(gf-nplus r^e
(gf-nminus (list 0 1))))) ))
3804 (append (gf-equal-degree-factors (list (gf-divide x f
) d
) q mult
)
3805 (gf-equal-degree-factors (list f d
) q mult
) ))))))
3807 ;; -----------------------------------------------------------------------------
3810 ;; gcd, gcdex and test of invertibility ----------------------------------------
3813 (defmfun $ef_gcd
(a b
)
3814 (ef-gf-field?
"ef_gcd")
3815 (let ((*ef-arith?
* t
))
3816 (gf-x2p (gf-gcd (gf-p2x a
) (gf-p2x b
))) ))
3818 (defmfun $gf_gcd
(a b
&optional p
)
3819 (let ((*ef-arith?
*))
3821 (p (unless (and (integerp p
) (primep p
))
3822 (gf-merror (intl:gettext
"`gf_gcd': ~m is not a prime number.") p
) )
3824 (let* ((*gf-char
* p
)
3826 (vars (caddar ($rat a
))) )
3827 (when (> (length vars
) 1)
3828 (gf-merror (intl:gettext
"`gf_gcd': Polynomials must be univariate.")) )
3829 (gf-x2p (gf-gcd (gf-p2x a
) (gf-p2x b
))) ))
3830 (t (gf-char?
"gf_gcd")
3831 (gf-x2p (gf-gcd (gf-p2x a
) (gf-p2x b
))) ))))
3834 (defmfun $gf_gcdex
(a b
)
3835 (gf-red?
"gf_gcdex")
3836 (let ((*ef-arith?
*))
3838 (mapcar #'gf-x2p
(gf-gcdex (gf-p2x a
) (gf-p2x b
) *gf-red
*)) )))
3840 (defmfun $ef_gcdex
(a b
)
3841 (ef-red?
"ef_gcdex")
3842 (let ((*ef-arith?
* t
))
3844 (mapcar #'gf-x2p
(gf-gcdex (gf-p2x a
) (gf-p2x b
) *gf-red
*)) )))
3847 (defmfun $gf_unit_p
(a)
3848 (gf-red?
"gf_unit_p")
3849 (let ((*ef-arith?
*))
3850 (gf-unit-p (gf-p2x a
) *gf-red
*) ))
3852 (defmfun $ef_unit_p
(a)
3853 (ef-red?
"ef_unit_p")
3854 (let ((*ef-arith?
* t
))
3855 (gf-unit-p (gf-p2x a
) *ef-red
*) ))
3857 (defun gf-unit-p (x red
)
3858 (= 0 (car (gf-gcd x red
))) )
3860 ;; -----------------------------------------------------------------------------
3863 ;; order -----------------------------------------------------------------------
3866 ;; group/element order
3868 (defmfun $gf_order
(&optional a
)
3869 (gf-data?
"gf_order")
3871 (a (let ((*ef-arith?
*))
3873 (when (and a
(or *gf-irred?
* (gf-unit-p a
*gf-red
*)))
3874 (gf-ord a
*gf-ord
* *gf-fs-ord
* *gf-red
*) )))
3877 (defmfun $ef_order
(&optional a
)
3878 (ef-data?
"ef_order")
3880 (a (let ((*ef-arith?
* t
))
3882 (when (and a
(or *ef-irred?
* (gf-unit-p a
*ef-red
*)))
3883 (gf-ord a
*ef-ord
* *ef-fs-ord
* *ef-red
*) )))
3886 ;; find the lowest value k for which a^k = 1
3888 (defun gf-ord (x ord fs-ord red
) ;; assume x # 0
3889 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3891 (declare (fixnum e
))
3892 (dolist (pe fs-ord ord
)
3894 e
(the fixnum
(cadr pe
))
3895 ord
(truncate ord
(expt p e
))
3896 z
(gf-pow$ x ord red
) ) ;; use exponentiation by precomputation
3899 (setq ord
(* ord p
))
3900 (when (= e
1) (return))
3902 (setq z
(gf-pow$ z p red
)) ))))
3904 (defun gf-ord-by-table (x)
3905 (let ((index (svref $gf_logs
(gf-x2n x
))))
3906 (truncate *gf-ord
* (gcd *gf-ord
* index
)) ))
3909 ;; Fq^n = F[x]/(f) is no field <=> f splits into factors
3911 ;; f = f1^e1 * ... * fk^ek where fi are irreducible of degree ni.
3913 ;; We compute the order of the group (F[x]/(fi^ei))* by
3915 ;; ((q^ni)^ei - (q^ni)^(ei-1)) = ((q^ni) - 1) * (q^ni)^(ei-1)
3917 ;; and ord((Fq^n)*) with help of the Chinese Remainder Theorem.
3919 (defun gf-group-order (q red
)
3920 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3921 (let (ne-list q^n
(e 0) (ord 1))
3922 (declare (fixnum e
))
3923 (do ((x (gf-factor red q
))) ;; red is assumed to be a monic poly
3925 (push (list (caar x
) (cadr x
)) ne-list
) ;; (list ni ei), f = prod(fi^ei) with fi of degree ni
3928 (setq q^n
(expt q
(the fixnum
(car a
)))
3929 e
(the fixnum
(cadr a
))
3930 ord
(* ord
(1- q^n
) (expt q^n
(the fixnum
(1- e
)))) ))
3933 ;; -----------------------------------------------------------------------------
3936 ;; degree, minimal polynomial, trace and norm ----------------------------------
3940 ;; degree: Find the lowest value d for which x^(q^d) = x
3942 (defun gf-degree-errchk (a n fun
)
3943 (when (and (not (null a
)) (>= (car a
) n
))
3944 (gf-merror (intl:gettext
"`~m': Leading exponent must be smaller than ~m.") fun n
) ))
3946 (defmfun $gf_degree
(a)
3947 (gf-field?
"gf_degree")
3948 (let ((*ef-arith?
*))
3950 (gf-degree-errchk a
*gf-exp
* "gf_degree")
3951 (*f-deg a
*gf-exp
* *gf-red
* *gf-x^p-powers
*) ))
3953 (defmfun $ef_degree
(a)
3954 (ef-field?
"ef_degree")
3955 (let ((*ef-arith?
* t
))
3957 (gf-degree-errchk a
*ef-exp
* "ef_degree")
3958 (*f-deg a
*ef-exp
* *ef-red
* *ef-x^q-powers
*) ))
3960 (defun *f-deg
(x n red x^q-powers
)
3963 (declare (fixnum d
))
3964 (when (equal x
(gf-compose (svref x^q-powers d
) x red
)) ;; f(x)^q = f(x^q)
3968 ;; produce the minimal polynomial
3970 (defmfun $gf_minimal_poly
(a)
3971 (gf-field?
"gf_minimal_poly")
3972 (let ((*ef-arith?
*))
3974 (gf-degree-errchk a
*gf-exp
* "gf_minimal_poly")
3975 (gf-minpoly a
*gf-red
* *gf-x^p-powers
*) ))
3977 (defmfun $ef_minimal_poly
(a)
3978 (ef-field?
"ef_minimal_poly")
3979 (let ((*ef-arith?
* t
))
3981 (gf-degree-errchk a
*ef-exp
* "ef_minimal_poly")
3982 (gf-minpoly a
*ef-red
* *ef-x^q-powers
*) ))
3986 ;; f(z) = (z - x) (z - x ) (z - x ) ... (z - x ) , where d = degree(x)
3988 (defun gf-minpoly (x red x^q-powers
)
3991 (powers (list (gf-minus x
)))
3992 (prod (list 0 (list 0 1)))
3993 xqi zx cx
) (declare (fixnum n
))
3995 ((= i n
)) (declare (fixnum i
))
3996 (setq xqi
(gf-compose (svref x^q-powers i
) x red
))
3997 (when (equal x xqi
) (return))
3998 (push (gf-nminus xqi
) powers
) )
3999 (dolist (pow powers
)
4000 (setq zx
(gf-zx prod
)
4001 cx
(gf-ncx pow prod red
)
4002 prod
(gf-nzx+cx zx cx
)) )
4003 ($substitute
'$z
'$x
(gf-x2p (gf-nxx2x prod
))) )))
4005 (defun gf-zx (x) ;; (gf-zx '(3 (5 1 3 1) 2 (4 1))) -> (4 (5 1 3 1) 3 (4 1))
4006 ;; 3 5 3 2 4 4 5 3 3 4
4007 ;; z (x + x ) + z x -> z (x + x ) + z x
4008 (do* ((res (list (1+ (car x
)) (cadr x
)))
4009 (r (cdr res
) (cddr r
))
4010 (rx (cddr x
) (cddr rx
)) )
4012 (rplacd r
(list (1+ (car rx
)) (cadr rx
))) ))
4014 (defun gf-ncx (c x red
) ;; modifies x
4015 ;; (gf-ncx '(1 1) '(3 (4 1 3 1) 2 (2 1)) '(6 1))
4016 ;; -> (3 (5 1 4 1) 2 (3 1))
4018 (do ((r (cdr x
) (cddr r
)))
4020 (rplaca r
(gf-times c
(car r
) red
)) )))
4022 (defun gf-nzx+cx
(zx cx
) ;; modifies zx
4024 (s (cdr cx
) (cddr s
)) r
+s
)
4025 ((null (cdr r
)) (nconc zx
(list 0 (car s
))))
4026 (setq r
+s
(gf-plus (caddr r
) (car s
)))
4028 (rplaca (setq r
(cddr r
)) r
+s
)
4029 (rplacd r
(cdddr r
)) )))
4031 (defun gf-nxx2x (xx) ;; modifies xx
4032 ;; (gf-nxx2x '(4 (0 3) 2 (0 1))) -> (4 3 2 1)
4033 (do ((r (cdr xx
) (cddr r
)))
4035 (rplaca r
(cadar r
)) ))
4040 ;; trace(a) = a + a + a + .. + a
4042 (defun $gf_trace
(a)
4043 (gf-field?
"gf_trace")
4044 (let ((*ef-arith?
*))
4045 (gf-trace (gf-p2x a
) *gf-red
* *gf-x^p-powers
*) ))
4047 (defun $ef_trace
(a)
4048 (ef-field?
"ef_trace")
4049 (let ((*ef-arith?
* t
))
4050 (gf-trace (gf-p2x a
) *ef-red
* *ef-x^q-powers
*) ))
4052 (defun gf-trace (x red x^q-powers
)
4056 ((= i n
) (gf-x2p su
)) (declare (fixnum i
))
4057 (setq su
(gf-plus su
(gf-compose (svref x^q-powers i
) x red
))) )))
4060 ;; 2 (n-1) n 2 (n-1)
4061 ;; 1 + q + q + .. + q (q - 1)/(q - 1) q q q
4062 ;; norm(a) = a = a = a * a * a * .. * a
4064 (defmfun $gf_norm
(a)
4065 (gf-field?
"gf_norm")
4066 (let ((*ef-arith?
*))
4067 (gf-norm (gf-p2x a
) *gf-red
* *gf-x^p-powers
*) ))
4069 (defmfun $ef_norm
(a)
4070 (ef-field?
"ef_norm")
4071 (let ((*ef-arith?
* t
))
4072 (gf-norm (gf-p2x a
) *ef-red
* *ef-x^q-powers
*) ))
4074 (defun gf-norm (x red x^q-powers
)
4078 ((= i n
) (gf-x2p prod
)) (declare (fixnum i
))
4079 (setq prod
(gf-times prod
(gf-compose (svref x^q-powers i
) x red
) red
)) )))
4081 ;; -----------------------------------------------------------------------------
4084 ;; normal elements and normal basis --------------------------------------------
4087 ;; Tests if an element is normal
4089 (defmfun $gf_normal_p
(a)
4090 (gf-field?
"gf_normal_p")
4091 (let ((*ef-arith?
*)) (gf-normal-p (gf-p2x a
))) )
4093 (defun gf-normal-p (x)
4095 (let ((modulus *gf-char
*)
4096 (mat (gf-maybe-normal-basis x
)) )
4097 (equal ($rank mat
) *gf-exp
*) )))
4099 (defmfun $ef_normal_p
(a)
4100 (ef-field?
"ef_normal_p")
4101 (let ((*ef-arith?
* t
)) (ef-normal-p (gf-p2x a
))) )
4103 (defun ef-normal-p (x)
4105 (let ((mat (ef-maybe-normal-basis x
)) )
4106 (/= 0 ($ef_determinant mat
)) )))
4109 ;; Finds a normal element e in the field; that is,
4110 ;; an element for which the list [e, e^q, e^(q^2), ... , e^(q^(n-1))] is a basis
4112 (defmfun $gf_normal
()
4113 (gf-field?
"gf_normal")
4114 (let ((*ef-arith?
*))
4115 (gf-x2p (gf-normal *gf-char
* *gf-exp
* #'gf-normal-p
)) ))
4117 (defmfun $ef_normal
()
4118 (ef-field?
"ef_normal")
4119 (let ((*ef-arith?
* t
))
4120 (gf-x2p (gf-normal *gf-card
* *ef-exp
* #'ef-normal-p
)) ))
4122 (defun gf-normal (q n normal-p-fn
)
4123 (let* ((inc (min $gf_coeff_limit q
))
4124 (i-lim (expt inc n
))
4126 (do ((i inc
(1+ i
)))
4128 (gf-merror (intl:gettext
"No normal element found.~%~\
4129 `gf_coeff_limit' might be too small.~%" )) )
4130 (setq x
(let ((*gf-char
* inc
)) (gf-n2x i
)))
4131 (when (funcall normal-p-fn x
) (return-from gf-normal x
)) )))
4134 ;; Finds a normal element in the field by producing random elements and checking
4135 ;; if each one is normal
4137 (defmfun $gf_random_normal
()
4138 (gf-field?
"gf_random_normal")
4139 (let ((*ef-arith?
*)) (gf-x2p (gf-random-normal))) )
4141 (defun gf-random-normal ()
4142 (do ((x (gf-random *gf-char
* *gf-exp
*) (gf-random *gf-char
* *gf-exp
*)))
4143 ((gf-normal-p x
) x
) ))
4145 (defmfun $ef_random_normal
()
4146 (ef-field?
"ef_random_normal")
4147 (let ((*ef-arith?
* t
)) (gf-x2p (ef-random-normal))) )
4149 (defun ef-random-normal ()
4150 (do ((x (gf-random *gf-card
* *ef-exp
*) (gf-random *gf-card
* *ef-exp
*)))
4151 ((ef-normal-p x
) x
) ))
4153 ;; Produces a normal basis as a matrix;
4154 ;; the columns are the coefficients of the powers e^(q^i) of the normal element
4156 (defmfun $gf_normal_basis
(a)
4157 (gf-field?
"gf_normal_basis")
4158 (let* ((*ef-arith?
*)
4161 (mat (gf-maybe-normal-basis x
)) )
4162 (unless (equal ($rank mat
) *gf-exp
*)
4163 (gf-merror (intl:gettext
"Argument to `gf_normal_basis' must be a normal element.")) )
4166 (defmfun $ef_normal_basis
(a)
4167 (ef-field?
"ef_normal_basis")
4168 (let* ((*ef-arith?
* t
)
4169 (mat (ef-maybe-normal-basis (gf-p2x a
))) )
4170 (unless (/= 0 ($ef_determinant mat
))
4171 (merror (intl:gettext
"Argument to `ef_normal_basis' must be a normal element." )) )
4174 (defun gf-maybe-normal-basis (x)
4175 (*f-maybe-normal-basis x
*gf-x^p-powers
* *gf-exp
* *gf-red
*) )
4177 (defun ef-maybe-normal-basis (x)
4178 (*f-maybe-normal-basis x
*ef-x^q-powers
* *ef-exp
* *ef-red
*) )
4180 (defun *f-maybe-normal-basis
(x x^q-powers e red
)
4181 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
4182 (declare (fixnum e
))
4183 (let ((e-1 (- e
1))) (declare (fixnum e-1
))
4186 #'(lambda (i j
) (declare (fixnum i j
))
4188 (gf-compose (svref x^q-powers
(1- i
)) x red
) e-1
) (1- j
)))
4191 ;; coefficients as an array of designated length
4193 (defun gf-x2array (x len
)
4194 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
4195 (declare (fixnum len
))
4196 (let ((cs (make-array (1+ len
) :initial-element
0)))
4197 (do ((k len
)) ((null x
) cs
) (declare (fixnum k
))
4199 ((> k
(the fixnum
(car x
)))
4201 ((= k
(the fixnum
(car x
)))
4202 (setf (svref cs
(- len k
)) (cadr x
))
4206 (setq x
(cddr x
)) ) ))))
4208 ;; Produces the normal representation of an element as a list of coefficients
4209 ;; Needs the inverted normal basis as the second argument
4210 ;; (the inversion might be time consuming)
4212 (defmfun $gf_normal_basis_rep
(a m-inv
)
4213 (gf-field?
"gf_normal_basis_rep")
4214 (let ((*ef-arith?
*))
4215 (gf-normal-basis-rep (gf-p2x a
) m-inv
*gf-exp
* '$gf_matmult
) ))
4217 (defmfun $ef_normal_basis_rep
(a m-inv
)
4218 (ef-field?
"ef_normal_basis_rep")
4219 (let ((*ef-arith?
* t
))
4220 (gf-normal-basis-rep (gf-p2x a
) m-inv
*ef-exp
* '$ef_matmult
) ))
4222 (defun gf-normal-basis-rep (x m-inv e matmult-fn
)
4223 (let* ((cs (cons '(mlist simp
) (gf-x2l x e
)))
4224 (nbrep (mfuncall matmult-fn m-inv cs
)) )
4225 (cons '(mlist simp
) (mapcar #'cadr
(cdr nbrep
))) ))
4227 ;; -----------------------------------------------------------------------------
4230 ;; functions for matrices ------------------------------------------------------
4233 (defmfun $gf_matneg
(m)
4234 (gf-char?
"gf_matneg")
4235 (mfuncall '$matrixmap
'$gf_neg m
) )
4237 (defmfun $ef_matneg
(m)
4238 (ef-gf-field?
"ef_matneg")
4239 (mfuncall '$matrixmap
'$ef_neg m
) )
4242 ;; matrix addition (convenience: mat, list or poly possible as argument)
4244 (defmfun $gf_matadd
(&rest args
)
4245 (let ((*ef-arith?
*))
4246 (reduce #'(lambda (m1 m2
) (gf-matadd m1 m2
'$gf_add
)) args
) ))
4248 (defmfun $ef_matadd
(&rest args
)
4249 (gf-data?
"ef_matadd")
4250 (let ((*ef-arith?
* t
))
4251 (reduce #'(lambda (m1 m2
) (gf-matadd m1 m2
'$ef_add
)) args
) ))
4253 (defun gf-matadd (m1 m2 add-fn
)
4254 (when ($listp m1
) (setq m1
($transpose m1
)))
4255 (when ($listp m2
) (setq m2
($transpose m2
)))
4257 ((and ($matrixp m1
) ($matrixp m2
))
4258 (gf-matadd2 m1 m2 add-fn
) )
4260 (gf-matadd1 m1 m2 add-fn
) ) ;; assumed without checking: m2 is poly
4262 (gf-matadd1 m2 m1 add-fn
) )
4264 (mfuncall add-fn m1 m2
) ) ))
4266 (defmfun gf-matadd1
(m poly add-fn
)
4267 (do ((r (cdr m
) (cdr r
)) new
)
4268 ((null r
) (cons '($matrix simp
) (nreverse new
)))
4269 (push (cons '(mlist simp
)
4270 (mapcar #'(lambda (p) (mfuncall add-fn p poly
)) (cdar r
)) )
4273 (defun gf-matadd2-error ()
4275 (intl:gettext
"Arguments to `~m' must have same formal structure.")
4276 (if *ef-arith?
* "ef_matadd" "gf_matadd") ))
4278 (defmfun gf-matadd2
(m1 m2 add-fn
)
4279 (setq m1
(cdr m1
) m2
(cdr m2
))
4280 (unless (= (length (car m1
)) (length (car m2
)))
4281 (gf-matadd2-error) )
4282 (do ((r1 m1
(cdr r1
)) (r2 m2
(cdr r2
)) new
)
4283 ((or (null r1
) (null r2
))
4284 (unless (and (null r1
) (null r2
))
4285 (gf-matadd2-error) )
4286 (cons '($matrix simp
) (nreverse new
)) )
4287 (push (cons '(mlist simp
) (mapcar add-fn
(cdar r1
) (cdar r2
))) new
) ))
4290 ;; matrix multiplication (convenience: mat, list or poly possible as argument)
4292 (defmfun $gf_matmult
(&rest args
)
4293 (gf-red?
"gf_matmult")
4294 (let ((*ef-arith?
*))
4295 (apply #'*f-matmult
`($gf_mult
,@args
)) ))
4297 (defmfun $ef_matmult
(&rest args
)
4298 (ef-red?
"ef_matmult")
4299 (let ((*ef-arith?
* t
))
4300 (apply #'*f-matmult
`($ef_mult
,@args
)) ))
4302 (defun *f-matmult
(mult-fn &rest args
)
4304 #'(lambda (m1 m2
) (gf-matmult m1 m2 mult-fn
))
4305 (cons '(mlist simp
) args
) ))
4307 (defun gf-matmult (m1 m2 mult-fn
)
4308 (when ($listp m1
) (setq m1
(list '($matrix simp
) m1
)))
4309 (when ($listp m2
) (setq m2
($transpose m2
)))
4311 ((and ($matrixp m1
) ($matrixp m2
))
4312 (gf-matmult2 m1 m2
) )
4314 (gf-matmult1 m1 m2 mult-fn
) ) ;; assumed without checking: m2 is poly
4316 (gf-matmult1 m2 m1 mult-fn
) )
4318 (mfuncall mult-fn m1 m2
) ) ))
4320 (defmfun gf-matmult1
(m poly mult-fn
)
4321 (do ((r (cdr m
) (cdr r
)) new
)
4322 ((null r
) (cons '($matrix simp
) (nreverse new
)))
4323 (push (cons '(mlist simp
)
4324 (mapcar #'(lambda (p) (mfuncall mult-fn p poly
)) (cdar r
)) )
4327 (defmfun gf-matmult2
(m1 m2
)
4328 (setq m1
(cdr m1
) m2
(cdr ($transpose m2
)))
4329 (unless (= (length (car m1
)) (length (car m2
)))
4331 (intl:gettext
"`~m': attempt to multiply non conformable matrices.")
4332 (if *ef-arith?
* "ef_matmult" "gf_matmult") ))
4333 (let ((red (if *ef-arith?
* *ef-red
* *gf-red
*)) )
4334 (do ((r1 m1
(cdr r1
)) new-mat
)
4336 (if (and (not (eq nil $scalarmatrixp
))
4337 (= 1 (length new-mat
)) (= 1 (length (cdar new-mat
))) )
4339 (cons '($matrix simp
) (nreverse new-mat
)) ))
4340 (do ((r2 m2
(cdr r2
)) new-row
)
4342 (push (cons '(mlist simp
) (nreverse new-row
)) new-mat
) )
4345 (mapcar #'(lambda (a b
) (gf-times (gf-p2x a
) (gf-p2x b
) red
))
4346 (cdar r1
) (cdar r2
) )))
4349 ;; -----------------------------------------------------------------------------
4352 ;; invert and determinant by lu ------------------------------------------------
4355 (defun zn-p-errchk (p fun pos
)
4356 (unless (and p
(integerp p
) (primep p
))
4357 (gf-merror (intl:gettext
"`~m': ~m argument must be prime number.") fun pos
) ))
4361 ;; returns nil when LU-decomposition fails
4362 (defun try-lu-and-call (fun m ring
)
4363 (let ((old-out *standard-output
*)
4364 (redirect (make-string-output-stream))
4366 (unwind-protect ;; protect against lu failure
4367 (setq *standard-output
* redirect
;; discard error messages from lu-factor
4368 res
(mfuncall fun m ring
) )
4370 (setq *standard-output
* old-out
)
4372 (return-from try-lu-and-call res
) )))
4374 (defmfun $zn_invert_by_lu
(m p
)
4375 (zn-p-errchk p
"zn_invert_by_lu" "Second")
4376 (let ((*ef-arith?
*) (*gf-char
* p
))
4377 (try-lu-and-call '$invert_by_lu m
'gf-coeff-ring
) ))
4379 (defmfun $gf_matinv
(m)
4380 (format t
"`gf_matinv' is deprecated. ~%~\
4381 The user is asked to use `gf_invert_by_lu' instead.~%" )
4382 ($gf_invert_by_lu m
) )
4384 (defmfun $gf_invert_by_lu
(m)
4385 (gf-field?
"gf_invert_by_lu")
4386 (let ((*ef-arith?
*)) (try-lu-and-call '$invert_by_lu m
'gf-ring
)) )
4388 (defmfun $ef_invert_by_lu
(m)
4389 (ef-field?
"ef_invert_by_lu")
4390 (let ((*ef-arith?
* t
)) (try-lu-and-call '$invert_by_lu m
'ef-ring
)) )
4394 (defmfun $zn_determinant
(m p
)
4395 (zn-p-errchk p
"zn_determinant" "Second")
4396 (let* ((*ef-arith?
*)
4398 (det (try-lu-and-call '$determinant_by_lu m
'gf-coeff-ring
)) )
4400 (mod (mfuncall '$determinant m
) p
) )))
4402 (defmfun $gf_determinant
(m)
4403 (gf-field?
"gf_determinant")
4404 (let* ((*ef-arith?
*)
4405 (det (try-lu-and-call '$determinant_by_lu m
'gf-ring
)) )
4407 (let (($matrix_element_mult
'$gf_mult
) ($matrix_element_add
'$gf_add
))
4408 (mfuncall '$determinant m
) ))))
4410 (defmfun $ef_determinant
(m)
4411 (ef-field?
"ef_determinant")
4412 (let* ((*ef-arith?
* t
)
4413 (det (try-lu-and-call '$determinant_by_lu m
'ef-ring
)) )
4415 (let (($matrix_element_mult
'$ef_mult
) ($matrix_element_add
'$ef_add
))
4416 (mfuncall '$determinant m
) ))))
4418 ;; -----------------------------------------------------------------------------
4421 ;; discrete logarithm ----------------------------------------------------------
4424 ;; solve g^x = a in Fq^n, where g a generator of (Fq^n)*
4426 (defmfun $gf_index
(a)
4427 (gf-data?
"gf_index")
4428 (gf-log-errchk1 *gf-prim
* "gf_index")
4429 (let ((*ef-arith?
*))
4431 ($zn_log a
(gf-x2n *gf-prim
*) *gf-char
*)
4432 (gf-dlog (gf-p2x a
)) )))
4434 (defmfun $ef_index
(a)
4435 (ef-data?
"ef_index")
4436 (gf-log-errchk1 *ef-prim
* "ef_index")
4437 (let ((*ef-arith?
* t
))
4440 (let ((*ef-arith?
*)) (gf-dlog (gf-n2x (cadr a
))))
4443 (defmfun $gf_log
(a &optional b
)
4445 (gf-log-errchk1 *gf-prim
* "gf_log")
4446 (let ((*ef-arith?
*))
4449 ($zn_log a
(if b b
(gf-x2n *gf-prim
*)) *gf-char
*) ) ;; $zn_log checks if b is primitive
4452 (and b
(setq b
(gf-p2x b
)) (gf-log-errchk2 b
#'gf-prim-p
"gf_log"))
4457 (defun gf-log-errchk1 (prim fun
)
4459 (gf-merror (intl:gettext
"`~m': there is no primitive element.") fun
) )
4460 (when (equal prim
'$unknown
)
4461 (gf-merror (intl:gettext
"`~m': a primitive element is not known.") fun
) ))
4463 (defun gf-log-errchk2 (x prim-p-fn fun
)
4464 (unless (funcall prim-p-fn x
)
4465 (gf-merror (intl:gettext
4466 "Second argument to `~m' must be a primitive element." ) fun
)))
4468 (defmfun $ef_log
(a &optional b
)
4470 (gf-log-errchk1 *ef-prim
* "ef_log")
4471 (let ((*ef-arith?
* t
))
4473 (and b
(setq b
(gf-p2x b
)) (gf-log-errchk2 b
#'ef-prim-p
"ef_log")) )
4476 (let ((*ef-arith?
*))
4477 (setq a
(gf-n2x (cadr a
)))
4479 (gf-dlogb a
(gf-n2x (cadr b
)))
4482 (let ((*ef-arith?
* t
))
4487 (defun gf-dlogb (a b
)
4488 (*f-dlogb a b
#'gf-dlog
*gf-ord
*) )
4490 (defun ef-dlogb (a b
)
4491 (*f-dlogb a b
#'ef-dlog
*ef-ord
*) )
4493 (defun *f-dlogb
(a b dlog-fn ord
)
4494 (let* ((a-ind (funcall dlog-fn a
)) (b-ind (funcall dlog-fn b
))
4495 (d (gcd (gcd a-ind b-ind
) ord
))
4496 (m (truncate ord d
)) )
4497 (zn-quo (truncate a-ind d
) (truncate b-ind d
) m
) ))
4499 ;; Pohlig and Hellman reduction
4502 (*f-dlog a
*gf-prim
* *gf-red
* *gf-ord
* *gf-fs-ord
*) )
4505 (*f-dlog a
*ef-prim
* *ef-red
* *ef-ord
* *ef-fs-ord
*) )
4507 (defun *f-dlog
(a g red ord fs-ord
)
4508 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
4510 ((or (null a
) (null g
)) nil
)
4511 ((>= (car a
) (car red
)) nil
)
4512 ((equal '(0 1) a
) 0)
4514 ((not (gf-unit-p a red
)) nil
)
4516 (let (p (e 0) ord
/p om xp xk dlogs mods
(g-inv (gf-inv g red
)))
4517 (declare (fixnum e
))
4519 (setq p
(car f
) e
(cadr f
)
4520 ord
/p
(truncate ord p
)
4521 om
(gf-pow g ord
/p red
)
4523 (do ((b a
) (k 0) (pk 1) (acc g-inv
) (e1 (1- e
)))
4524 (()) (declare (fixnum k
))
4525 (setq xk
(gf-dlog-rho-brent (gf-pow b ord
/p red
) om p red
))
4528 (when (= k e
) (return))
4529 (setq ord
/p
(truncate ord
/p p
)
4531 (when (/= xk
0) (setq b
(gf-times b
(gf-pow acc xk red
) red
)))
4532 (when (/= k e1
) (setq acc
(gf-pow acc p red
))) )
4533 (push (expt p e
) mods
)
4535 (car (chinese dlogs mods
)) ))))
4537 ;; iteration for Pollard rho: b = g^y * a^z in each step
4539 (defun gf-dlog-f (b y z a g p red
)
4540 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
4541 (let ((m (mod (cadr b
) 3))) (declare (fixnum m
))
4544 (values (gf-sq b red
) (mod (ash y
1) p
) (mod (ash z
1) p
)) )
4545 ((= 1 m
) ;; avoid stationary case b=1 => b^2=1
4546 (values (gf-times g b red
) (mod (+ y
1) p
) z
) )
4548 (values (gf-times a b red
) y
(mod (+ z
1) p
) ) ) )))
4552 (defun gf-dlog-naive (a g red
)
4554 (gi '(0 1) (gf-times gi g red
)) )
4557 ;; baby-steps-giant-steps:
4559 (defun gf-dlog-baby-giant (a g p red
) ;; g is generator of order prime p
4560 (let* ((m (1+ (isqrt p
)))
4561 (s (floor (* 1.3 m
)))
4565 (make-hash-table :size s
:test
#'equal
:rehash-threshold
0.9) )
4568 (when (equal '(0 1) b
)
4570 (return-from gf-dlog-baby-giant r
) )
4571 (setf (gethash b babies
) r
)
4573 (when (= r m
) (return))
4574 (setq b
(gf-times gi b red
)) )
4575 (setq g^m
(gf-pow g m red
))
4577 (bb (list 0 1) (gf-times g^m bb red
))
4579 (when (setq r
(gethash bb babies
))
4581 (return (+ r
(* rr m
))) )) ))
4583 ;; Pollard rho for dlog computation (Brents variant of collision detection)
4585 (defun gf-dlog-rho-brent (a g p red
) ;; g is generator of order p
4586 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
4588 ((equal '(0 1) a
) 0)
4590 ((equal a
(gf-sq g red
)) 2)
4591 ((equal '(0 1) (gf-times a g red
)) (1- p
))
4592 ((< p
32) (gf-dlog-naive a g red
))
4593 ((< p
1024) (gf-dlog-baby-giant a g p red
))
4595 (prog ((b (list 0 1)) (y 0) (z 0) ;; b = g^y * a^z
4596 (bb (list 0 1)) (yy 0) (zz 0) ;; bb = g^yy * a^zz
4599 (do ((i 0)(j 1)) (())
4600 (declare (fixnum i j
))
4601 (multiple-value-setq (b y z
) (gf-dlog-f b y z a g p red
))
4602 (when (equal b bb
) (return)) ;; g^y * a^z = g^yy * a^zz
4605 (setq j
(1+ (ash j
1)))
4606 (setq bb b yy y zz z
) ))
4607 (setq dy
(mod (- yy y
) p
) dz
(mod (- z zz
) p
)) ;; g^dy = a^dz = g^(x*dz)
4608 (when (= 1 (gcd dz p
))
4609 (return (zn-quo dy dz p
)) ) ;; x = dy/dz mod p (since g is generator of order p)
4613 yy
(1+ (random (1- p
)))
4614 zz
(1+ (random (1- p
)))
4615 bb
(gf-times (gf-pow g yy red
) (gf-pow a zz red
) red
) )
4618 ;; -----------------------------------------------------------------------------
4621 ;; nth root in Galois Fields ---------------------------------------------------
4624 (defmfun $ef_nth_root
(a r
)
4625 (ef-field?
"ef_nth_root")
4626 (unless (and (integerp r
) (> r
0))
4627 (gf-merror (intl:gettext
"Second argument to `ef_nth_root' must be a positive integer. Found ~m.") a r
) )
4628 (let* ((*ef-arith?
* t
)
4629 (rts (gf-nrt (gf-p2x a
) r
*ef-red
* *ef-ord
*)) )
4630 (gf-nrt-exit rts
) ))
4632 (defmfun $gf_nth_root
(a r
)
4633 (gf-field?
"gf_nth_root")
4634 (unless (and (integerp r
) (> r
0))
4635 (gf-merror (intl:gettext
"Second argument to `gf_nth_root' must be a positive integer. Found ~m.") a r
) )
4636 (let* ((*ef-arith?
*)
4637 (rts (gf-nrt (gf-p2x a
) r
*gf-red
* *gf-ord
*)) )
4638 (gf-nrt-exit rts
) ))
4640 (defun gf-nrt-exit (rts)
4642 (setq rts
(mapcar #'gf-n2x
(sort (mapcar #'gf-x2n rts
) #'<)))
4643 (cons '(mlist simp
) (mapcar #'gf-x2p rts
)) ))
4645 ;; e.g. r=i*i*j*k, then x^(1/r) = (((x^(1/i))^(1/i))^(1/j))^(1/k)
4646 (defun gf-nrt (x r red ord
)
4647 (setq x
(gf-nred x red
))
4651 ((or (= 1 r
) (primep r
)) (setq rts
(gf-amm x r red ord
)))
4653 (let* (($intfaclim
) (rs (get-factor-list r
)))
4654 (setq rs
(sort rs
#'< :key
#'car
))
4658 #'(lambda (pe) (apply #'(lambda (p e
) (make-list e
:initial-element p
)) pe
))
4660 (setq rts
(gf-amm x
(car rs
) red ord
))
4661 (dolist (r (cdr rs
))
4662 (setq rts
(apply #'nconc
(mapcar #'(lambda (y) (gf-amm y r red ord
)) rts
))) ))))
4665 ;; inspired by Bach,Shallit 7.3.2
4666 (defun gf-amm (x r red ord
) ;; r prime, red irreducible
4669 (let (k n e u s m re xr xu om g br bu ab alpha beta rt
)
4672 ((and (= 0 (setq m
(mod ord
2)))
4673 (/= 1 (gf-jacobi x red
(if *ef-arith?
* *gf-card
* *gf-char
*))) )
4674 (return-from gf-amm nil
) )
4675 ((= 1 m
) ;; q = 2^n : unique solution
4677 `(,(gf-pow x
(ash (+ (ash ord
1) 2) -
2) red
)) ))
4679 (setq rt
(gf-pow x
(ash (+ ord
2) -
2) red
))
4680 (return-from gf-amm
`(,rt
,(gf-minus rt
))) )
4682 (let* ((twox (gf-plus x x
))
4683 (y (gf-pow twox
(ash (- ord
4) -
3) red
))
4684 (i (gf-times twox
(gf-times y y red
) red
))
4685 (rt (gf-times x
(gf-times y
(gf-nplus i
`(0 ,(gf-cminus-b 1))) red
) red
)) )
4686 (return-from gf-amm
`(,rt
,(gf-minus rt
))) ))))
4687 (multiple-value-setq (s m
) (truncate ord r
))
4688 (when (and (= 0 m
) (not (equal '(0 1) (gf-pow x s red
))))
4689 (return-from gf-amm nil
))
4690 ;; r = 3, first 2 cases:
4693 ((= 1 (setq m
(mod ord
3))) ;; unique solution
4695 `(,(gf-pow x
(truncate (1+ (ash ord
1)) 3) red
)) ))
4696 ((= 2 m
) ;; unique solution
4698 `(,(gf-pow x
(truncate (1+ ord
) 3) red
)) ))))
4699 ;; compute u,e with ord = u*r^e and r,u coprime:
4702 (multiple-value-setq (u1 m
) (truncate u1 r
))
4703 (when (/= 0 m
) (return))
4704 (setq u u1 e
(1+ e
)) )
4707 (setq rt
(gf-pow x
(inv-mod r u
) red
)) ;; unique solution, see Bach,Shallit 7.3.1
4711 (do () ((not (equal '(0 1) (gf-pow n s red
)))) ;; n is no r-th power
4712 (setq n
(gf-n2x (1+ (gf-x2n n
)))) )
4713 (setq g
(gf-pow n u red
)
4715 om
(gf-pow g
(truncate re r
) red
) ) ;; r-th root of unity
4717 ((or (/= 3 r
) (= 0 (setq m
(mod ord
9))))
4718 (setq xr
(gf-pow x u red
)
4719 xu
(gf-pow x re red
)
4720 k
(*f-dlog xr g red re
`((,r
,e
))) ;; g^k = xr
4721 br
(gf-pow g
(truncate k r
) red
) ;; br^r = xr
4722 bu
(gf-pow xu
(inv-mod r u
) red
) ;; bu^r = xu
4723 ab
(cdr (zn-gcdex1 u re
))
4726 (if (< alpha
0) (incf alpha ord
) (incf beta ord
))
4727 (setq rt
(gf-times (gf-pow br alpha red
) (gf-pow bu beta red
) red
)) )
4728 ;; r = 3, remaining cases:
4730 (setq rt
(gf-pow x
(truncate (+ (ash ord
1) 3) 9) red
)) )
4732 (setq rt
(gf-pow x
(truncate (+ ord
3) 9) red
)) ))
4733 (do ((i 1 (1+ i
)) (j (list 0 1)) (res (list rt
)))
4735 (setq j
(gf-times j om red
))
4736 (push (gf-times rt j red
) res
) ))))))
4738 ;; -----------------------------------------------------------------------------
4741 ;; tables of small fields ------------------------------------------------------
4744 (defmfun $gf_add_table
()
4745 (gf-data?
"gf_add_table")
4746 (let ((*ef-arith?
*)) (gf-add-table *gf-card
*)) )
4748 (defmfun $ef_add_table
()
4749 (ef-data?
"ef_add_table")
4750 (let ((*ef-arith?
* t
)) (gf-add-table *ef-card
*)) )
4752 (defun gf-add-table (card)
4755 (gf-x2n (gf-plus (gf-n2x (1- i
)) (gf-n2x (1- j
)))) )
4759 (defmfun $gf_mult_table
(&optional all?
)
4760 (gf-data?
"gf_mult_table")
4761 (let ((*ef-arith?
*))
4762 (gf-mult-table *gf-red
* *gf-irred?
* *gf-card
* all?
) ))
4764 (defmfun $ef_mult_table
(&optional all?
)
4765 (ef-data?
"ef_mult_table")
4766 (let ((*ef-arith?
* t
))
4767 (gf-mult-table *ef-red
* *ef-irred?
* *ef-card
* all?
) ))
4769 (defun gf-mult-table (red irred? card all?
)
4772 ((or irred?
;; field
4773 (equal all?
'$all
) )
4776 (gf-x2n (gf-times (gf-n2x i
) (gf-n2x j
) red
)))
4780 (do ((i 1 (1+ i
)) x
)
4783 (when (gf-unit-p x red
) (push x units
)) )
4784 (dolist (x units
(cons '($matrix simp
) (nreverse res
)))
4787 (mapcar #'(lambda (y) (gf-x2n (gf-times x y red
))) units
) )
4790 (defmfun $gf_power_table
(&rest args
)
4791 (gf-data?
"gf_power_table")
4792 (let ((*ef-arith?
*) all? cols
)
4793 (multiple-value-setq (all? cols
)
4794 (apply #'gf-power-table-args
(cons "gf_power_table" args
)) )
4796 (setq cols
*gf-ord
*)
4797 (when all?
(incf cols
)) )
4798 (gf-power-table *gf-red
* *gf-irred?
* *gf-card
* cols all?
) ))
4800 (defmfun $ef_power_table
(&rest args
)
4801 (ef-data?
"ef_power_table")
4802 (let ((*ef-arith?
* t
) all? cols
)
4803 (multiple-value-setq (all? cols
)
4804 (apply #'gf-power-table-args
(cons "ef_power_table" args
)) )
4806 (setq cols
*ef-ord
*)
4807 (when all?
(incf cols
)) )
4808 (gf-power-table *ef-red
* *ef-irred?
* *ef-card
* cols all?
) ))
4810 (defun gf-power-table-args (&rest args
)
4811 (let ((str (car args
)) all? cols
(x (cadr args
)) (y (caddr args
)))
4814 ((integerp x
) (setq cols x
))
4815 ((equal x
'$all
) (setq all? t
))
4816 (t (gf-merror (intl:gettext
4817 "First argument to `~m' must be `all' or a small fixnum." ) str
))))
4820 ((and (integerp x
) (equal y
'$all
)) (setq all? t
))
4821 ((and (equal x
'$all
) (integerp y
)) (setq cols y
))
4822 (t (format t
"Only the first argument to `~a' has been used.~%" str
) )))
4823 (values all? cols
) ))
4825 (defun gf-power-table (red irred? card cols all?
)
4829 #'(lambda (i j
) (gf-x2n (gf-pow (gf-n2x i
) j red
)))
4833 (do ((i 1 (1+ i
)) x res
)
4834 ((= i card
) (cons '($matrix simp
) (nreverse res
)))
4836 (when (gf-unit-p x red
)
4839 (mapcar #'(lambda (j) (gf-x2n (gf-pow x j red
)))
4840 (cdr (mfuncall '$makelist
'$j
'$j
1 cols
)) ))
4843 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;