1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancements. ;;;;;
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 (load-macsyma-macros rzmac
)
21 ;;; Sum of divisors and Totient functions
23 ;; compute the sum of the k'th powers of the divisors of the absolute
26 (defmfun $divsum
(n &optional
(k 1))
27 (if (and (integerp k
) (integerp n
))
30 (list '(rat) (divsum n
(- k
)) (expt n
(- k
)))
32 (list '($divsum
) n k
)))
34 ;; divsum assumes its arguments to be non-negative integers.
37 (declare (type (integer 0) n k
) (optimize (speed 3)))
38 (let (($intfaclim nil
)) ;get-factor-list returns list
39 ;of (p_rime e_xponent) pairs
42 ((zerop k
) (reduce #'* (get-factor-list n
) ; product over e+1
43 :key
#'(lambda (pe) (1+ (the fixnum
(cadr pe
))))))
44 (t (reduce #'* (get-factor-list n
) ; product over ((p^k)^(e+1)-1)/(p^k-1)
46 (let ((p (car pe
)) (e (cadr pe
)))
47 (declare (type (integer 2) p
)
48 (type (integer 1 (#.most-positive-fixnum
)) e
))
49 (let ((tmp (expt p k
)))
50 (truncate (1- (expt tmp
(1+ e
)))
53 ;; totient computes the euler totient function
54 ;; i.e. the count of numbers relatively prime to n between 1 and n.
59 (list '($totient
) n
)))
61 ;; totient assumes its argument to be an integer.
62 ;; the exponents in the prime factorization of n are assumed to be
63 ;; fixnums (anything else would exceed memory).
66 (declare (type (integer 0) n
) (optimize (speed 3)))
67 (let (($intfaclim nil
))
70 (reduce #'* (get-factor-list n
)
72 (let ((p (car pe
)) (e (cadr pe
)))
73 (declare (type (integer 2) p
)
74 (type (integer 1 (#.most-positive-fixnum
)) e
))
75 (* (1- p
) (expt p
(1- e
)))))))))
77 ;;; JACOBI symbol and Gaussian factoring
79 ;; $jacobi/jacobi implement the Kronecker-Jacobi symbol, a light
80 ;; generalization of the Legendre/Jacobi symbols.
81 ;; (for a prime b, $jacobi(a b) is the Legendre symbol).
83 ;; The implementation follows algorithm 1.4.10 in 'A Course in
84 ;; Computational Algebraic Number Theory' by H. Cohen
86 (defmfun $jacobi
(a b
)
87 (if (and (integerp a
) (integerp b
))
92 (declare (integer a b
) (optimize (speed 3)))
94 (if (= 1 (abs a
)) 1 0))
95 ((and (evenp a
) (evenp b
))
99 (tab2 (make-array 8 :element-type
'(integer -
1 1)
100 :initial-contents
#(0 1 0 -
1 0 -
1 0 1))))
101 (declare (type (integer -
1 1) k
))
103 (loop for v fixnum
= 0 then
(1+ v
) ;remove 2's from b
104 while
(evenp b
) do
(setf b
(ash b -
1))
105 finally
(when (oddp v
)
106 (setf k
(aref tab2
(logand a
7))))) ; (-1)^(a^2-1)/8
115 (return-from jacobi
(if (> b
1) 0 k
)))
117 (loop for v fixnum
= 0 then
(1+ v
)
118 while
(evenp a
) do
(setf a
(ash a -
1))
119 finally
(when (oddp v
)
120 (when (minusp (aref tab2
(logand b
7))); (-1)^(b^2-1)/8
123 (when (plusp (logand a b
2)) ;compute (-1)^(a-1)(b-1)/4
131 ;; factor over the gaussian primes
133 (declaim (inline gctimes gctime1
))
135 (defmfun $gcfactor
(n)
136 (let ((n (cdr ($totaldisrep
($bothcoef
($rat
($rectform n
) '$%i
) '$%i
)))))
137 (if (not (and (integerp (first n
)) (integerp (second n
))))
138 (gcdisp (nreverse n
))
139 (loop for
(term exp
) on
(gcfactor (second n
) (first n
)) by
#'cddr
143 (list '(mexpt simp
) (gcdisp term
) exp
))
146 (return (cond ((null res
)
149 (if (mexptp (car res
))
150 `((mexpt simp gcfactored
) ,@(cdar res
))
153 `((mtimes simp gcfactored
) ,@(nreverse res
)))))))))
156 (declare (integer p
) (optimize (speed 3)))
157 (cond ((not (= (rem p
4) 1)) nil
)
158 ((= (rem p
8) 5) (power-mod 2 (ash (1- p
) -
2) p
))
159 ((= (rem p
24) 17) (power-mod 3 (ash (1- p
) -
2) p
)) ;p=2(mod 3)
160 (t (do ((i 5 (+ i j
)) ;p=1(mod 24)
162 ((= (jacobi i p
) -
1) (power-mod i
(ash (1- p
) -
2) p
))
163 (declare (integer i
) (fixnum j
))))))
166 (declare (integer p
) (optimize (speed 3)))
175 ((not (> r1 sp
)) (list r1 r2
))
176 (declare (integer r1 r2
)))))))
178 (defun gctimes (a b c d
)
179 (declare (integer a b c d
) (optimize (speed 3)))
180 (list (- (* a c
) (* b d
))
181 (+ (* a d
) (* b c
))))
186 (let ((rp (car term
))
188 (setq ip
(if (eql ip
1) '$%i
`((mtimes) ,ip $%i
)))
191 `((mplus) ,rp
,ip
)))))
193 (defun gcfactor (a b
)
194 (declare (integer a b
) (optimize (speed 3)))
195 (when (and (zerop a
) (zerop b
))
196 (return-from gcfactor
(list 0 1)))
197 (let* (($intfaclim nil
)
205 (nl (cfactorw (+ (* a a
) (* b b
))))
211 (declare (integer e1 e2 econt g a b
))
212 (when (= 1 (the integer
(car gl
))) (setq gl nil
))
213 (when (= 1 (the integer
(car nl
))) (setq nl nil
))
223 (setq p
(max (the integer
(car gl
))
224 (the integer
(car nl
))))))
227 (setq plis
(list* p
(cadr gl
) plis
))
231 (cond ((zerop (rem (+ (* a
(the integer
(car cd
))) ; gcremainder
232 (* b
(the integer
(cadr cd
))))
233 (the integer p
))) ; remainder(real((a+bi)cd~),p)
234 ; z~ is complex conjugate
239 (setq dc
(reverse cd
))))
240 (setq dc
(gcexpt dc
(the integer
(cadr nl
)))
241 dc
(gctimes a b
(the integer
(car dc
)) (- (the integer
(cadr dc
))))
242 a
(truncate (the integer
(car dc
)) (the integer p
))
243 b
(truncate (the integer
(cadr dc
)) (the integer p
))
245 (when (equal p
(car gl
))
246 (incf econt
(the integer
(cadr gl
)))
248 (incf e1
(* 2 (the integer
(cadr gl
)))))
250 (incf e1
(the integer
(cadr gl
)))
251 (incf e2
(the integer
(cadr gl
)))))
254 (setq ans
(list* cd e1 ans
))
257 (setq ans
(list* (reverse cd
) e2 ans
))
262 (let* ((cd (gcexpt (list 0 -
1) (rem econt
4)))
265 (l (mapcar #'signum
(gctimes a b rcd icd
)))
268 (declare (integer r i rcd icd
))
269 (when (or (= r -
1) (= i -
1))
270 (setq plis
(list* -
1 1 plis
)))
272 (setq ans
(list* '(0 1) 1 ans
)))
273 (return-from gcfactor
(append plis ans
))))))
276 (declare (optimize (speed 3)))
279 (declare (integer r i
))
280 (list (+ (* r r
) (* i i
)) (ash (* r i
) 1))))
283 (gctimes (car a
) (cadr a
) (car b
) (cadr b
)))
286 (cond ((zerop n
) '(1 0))
288 ((evenp n
) (gcexpt (gcsqr a
) (ash n -
1)))
289 (t (gctime1 a
(gcexpt (gcsqr a
) (ash n -
1))))))
291 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
293 ;; Maxima functions in (Z/nZ)*
295 ;; zn_order, zn_primroot_p, zn_primroot, zn_log,
296 ;; solve_congruences, zn_characteristic_factors, zn_factor_generators, zn_nth_root,
297 ;; zn_add_table, zn_mult_table, zn_power_table
299 ;; 2012 - 2020, Volker van Nek
302 ;; Maxima option variables:
303 (defmvar $zn_primroot_limit
1000 "Upper bound for `zn_primroot'." fixnum
)
304 (defmvar $zn_primroot_verbose nil
"Print message when `zn_primroot_limit' is reached." boolean
)
305 (defmvar $zn_primroot_pretest nil
"`zn_primroot' pretests whether (Z/nZ)* is cyclic." boolean
)
307 (declaim (inline zn-quo
))
308 (defun zn-quo (n d p
)
309 (declare (integer n d p
) (optimize (speed 3)))
310 (mod (* n
(inv-mod d p
)) p
) )
312 ;; compute the order of x in (Z/nZ)*
314 ;; optional argument: ifactors of totient(n) as returned in Maxima by
315 ;; block([factors_only:false], ifactors(totient(n)))
316 ;; e.g. [[2, 3], [3, 1], ... ]
318 (defmfun $zn_order
(x n
&optional fs-phi
)
319 (unless (and (integerp x
) (integerp n
))
320 (return-from $zn_order
322 (list '($zn_order
) x n fs-phi
)
323 (list '($zn_order
) x n
) )))
327 ((= 1 x
) (if (= n
1) nil
1))
328 ((/= 1 (gcd x n
)) nil
)
331 (if (and ($listp fs-phi
) ($listp
(cadr fs-phi
)))
333 (setq fs-phi
(mapcar #'cdr
(cdr fs-phi
))) ; Lispify fs-phi
334 (setq fs-phi
(cons (totient-from-factors fs-phi
) fs-phi
)) )
335 (gf-merror (intl:gettext
336 "Third argument to `zn_order' must be of the form [[p1, e1], ..., [pk, ek]]." )))
337 (setq fs-phi
(totient-with-factors n
)) )
341 (cdr fs-phi
)) ))) ;; factors of phi with multiplicity
343 (defun zn_order (x n phi fs-phi
)
344 (format t
"`zn_order' is deprecated. ~%Please use `zn-order' instead.~%" )
345 (zn-order x n phi fs-phi
) )
347 ;; compute order of x as a divisor of the known group order
349 (defun zn-order (x n ord fs-ord
)
351 (dolist (f fs-ord ord
)
352 (setq p
(car f
) e
(cadr f
)
353 ord
(truncate ord
(expt p e
))
354 z
(power-mod x ord n
) )
355 ;; ord(z) = p^i, i from [0,e]
356 ;; replace p^e in ord by p^i : x^(ord*p^i/p^e) = 1
360 (when (= e
1) (return))
362 (setq z
(power-mod z p n
)) ))))
365 ;; compute totient (euler-phi) of n and its factors in one function
367 ;; returns a list of the form (phi ((p1 e1) ... (pk ek)))
369 (defun totient-with-factors (n)
370 (let (($intfaclim
) (phi 1) fs-n
(fs) p e
(fs-phi) g
)
371 (setq fs-n
(get-factor-list n
))
373 (setq p
(car f
) e
(cadr f
))
374 (setq phi
(* phi
(1- p
) (expt p
(1- e
))))
375 (when (> e
1) (setq fs
(cons `(,p
,(1- e
)) fs
)))
376 (setq fs
(append (get-factor-list (1- p
)) fs
)) )
377 (setq fs
(copy-tree fs
)) ;; this deep copy is a workaround to avoid references
378 ;; to the list returned by ifactor.lisp/get-factor-list.
380 (setq fs
(sort fs
#'< :key
#'car
))
382 (dolist (f (cdr fs
) (cons phi
(reverse (cons g fs-phi
))))
383 (if (= (car f
) (car g
))
384 (incf (cadr g
) (cadr f
)) ;; assignment
386 (setq fs-phi
(cons g fs-phi
))
389 ;; recompute totient from given factors
391 ;; fs-phi: factors of totient with multiplicity: ((p1 e1) ... (pk ek))
393 (defun totient-from-factors (fs-phi)
395 (dolist (f fs-phi phi
)
396 (setq p
(car f
) e
(cadr f
))
397 (setq phi
(* phi
(expt p e
))) )))
400 ;; for n > 2 is x a primitive root modulo n
401 ;; when n does not divide x
402 ;; and for all prime factors p of phi = totient(n)
403 ;; x^(phi/p) mod n # 1
405 ;; optional argument: ifactors of totient(n)
407 (defmfun $zn_primroot_p
(x n
&optional fs-phi
)
408 (unless (and (integerp x
) (integerp n
))
409 (return-from $zn_primroot_p
411 (list '($zn_primroot_p
) x n fs-phi
)
412 (list '($zn_primroot_p
) x n
) )))
416 ((= 1 x
) (if (= n
2) t nil
))
420 (if (and ($listp fs-phi
) ($listp
(cadr fs-phi
)))
422 (setq fs-phi
(mapcar #'cdr
(cdr fs-phi
))) ; Lispify fs-phi
423 (setq fs-phi
(cons (totient-from-factors fs-phi
) fs-phi
)) )
424 (gf-merror (intl:gettext
425 "Third argument to `zn_primroot_p' must be of the form [[p1, e1], ..., [pk, ek]]." )))
426 (setq fs-phi
(totient-with-factors n
)) )
429 (mapcar #'car
(cdr fs-phi
))) ))) ;; factors only (omitting multiplicity)
431 (defun zn-primroot-p (x n phi fs-phi
)
432 (unless (= 1 (gcd x n
))
433 (return-from zn-primroot-p nil
) )
435 (when (= 1 (power-mod x
(truncate phi p
) n
))
436 (return-from zn-primroot-p nil
) )))
439 ;; find the smallest primitive root modulo n
441 ;; optional argument: ifactors of totient(n)
443 (defmfun $zn_primroot
(n &optional fs-phi
)
445 (return-from $zn_primroot
447 (list '($zn_primroot
) n fs-phi
)
448 (list '($zn_primroot
) n
) )))
453 (when $zn_primroot_pretest
455 (return-from $zn_primroot nil
) ))
457 (if (and ($listp fs-phi
) ($listp
(cadr fs-phi
)))
459 (setq fs-phi
(mapcar #'cdr
(cdr fs-phi
))) ; Lispify fs-phi
460 (setq fs-phi
(cons (totient-from-factors fs-phi
) fs-phi
)) )
461 (gf-merror (intl:gettext
462 "Second argument to `zn_primroot' must be of the form [[p1, e1], ..., [pk, ek]]." )))
463 (setq fs-phi
(totient-with-factors n
)) )
466 (mapcar #'car
(cdr fs-phi
))) ))) ;; factors only (omitting multiplicity)
468 ;; (Z/nZ)* is cyclic if n = 2, 4, p^k or 2*p^k where p prime > 2
471 (when (< n
2) (return))
472 (when (< n
8) (return t
)) ;; 2,3,4,5,2*3,7
473 (when (evenp n
) ;; 2*p^k
474 (setq n
(ash n -
1)) ;; -> p^k
475 (when (evenp n
) (return)) )
476 (let (($intfaclim
) fs
(len 0))
477 (multiple-value-setq (n fs
) (get-small-factors n
))
478 (when fs
(setq len
(length fs
)))
479 (when (= 1 n
) (return (= 1 len
)))
480 (when (> len
0) (return))
481 (when (primep n
) (return t
))
482 (setq fs
(convert-list (get-large-factors n
)))
483 (return (= 1 (length fs
))) )))
485 (defun zn-primroot (n phi fs-phi
)
488 (when (zn-primroot-p i n phi fs-phi
)
490 (when (= i $zn_primroot_limit
)
491 (when $zn_primroot_verbose
492 (format t
"`zn_primroot' stopped at zn_primroot_limit = ~A~%" $zn_primroot_limit
) )
496 ;; Chinese Remainder Theorem
499 (defmfun ($chinese
:deprecated-p $solve_congruences
) (&rest a
)
500 (apply '$solve_congruences a
))
502 (defmfun $solve_congruences
(rems mods
&optional
(return-lcm? nil
))
504 ((not (and ($listp rems
) ($listp mods
)))
505 (list '($solve_congruences
) rems mods
) )
506 ((let ((lr ($length rems
)) (lm ($length mods
)))
507 (or (= 0 lr
) (= 0 lm
) (/= lr lm
)) )
508 (gf-merror (intl:gettext
509 "Unsuitable arguments to `solve_congruences': ~m ~m" ) rems mods
))
510 ((notevery #'integerp
(setq rems
(cdr rems
)))
511 (list '($solve_congruences
) (cons '(mlist simp
) rems
) mods
) )
512 ((notevery #'integerp
(setq mods
(cdr mods
)))
513 (list '($solve_congruences
) (cons '(mlist simp
) rems
) (cons '(mlist simp
) mods
)) )
514 ((eql return-lcm?
'$lcm
)
515 (cons '(mlist simp
) (solve-congruences rems mods
)) )
517 (car (solve-congruences rems mods
)) )))
519 (defun solve-congruences (rems mods
)
520 (if (= 1 (length mods
))
521 (list (car rems
) (car mods
))
522 (let ((rp (car rems
))
524 (rq-q (solve-congruences (cdr rems
) (cdr mods
))) )
526 (let* ((rq (car rq-q
))
530 (c (cadr gc
)) ) ;; CRT-coefficient
532 ((= 1 g
) ;; coprime moduli
533 (let* ((h (mod (* (- rp rq
) c
) p
))
536 ((= 0 (mod (- rp rq
) g
)) ;; ensures unique solution
537 (let* ((h (* (- rp rq
) c
))
540 (list (mod (+ rq
(* h q
/g
)) lcm-pq
) lcm-pq
) ))))))))
542 ;; (zn-gcdex2 x y) returns `(,g ,c) where c*x + d*y = g = gcd(x,y)
544 (defun zn-gcdex2 (x y
)
545 (let ((x1 1) (y1 0) q r
)
546 (do ()((= 0 y
) (list x x1
))
547 (multiple-value-setq (q r
) (truncate x y
))
549 (psetf x1 y1 y1
(- x1
(* q y1
))) )))
552 ;; discrete logarithm:
553 ;; solve g^x = a mod n, where g is a generator of (Z/nZ)* or of a subgroup containing a
555 ;; see: lecture notes 'Grundbegriffe der Kryptographie' - Eike Best
556 ;; http://theoretica.informatik.uni-oldenburg.de/~best/publications/kry-Mai2005.pdf
558 ;; optional argument: ifactors of zn_order(g,n)
560 (defmfun $zn_log
(a g n
&optional fs-ord
)
561 (unless (and (integerp a
) (integerp g
) (integerp n
))
564 (list '($zn_log
) a g n fs-ord
)
565 (list '($zn_log
) a g n
) )))
566 (when (minusp a
) (setq a
(mod a n
)))
568 ((or (= 0 a
) (>= a n
)) nil
)
571 ((> (gcd a n
) 1) nil
)
574 (if (and ($listp fs-ord
) ($listp
(cadr fs-ord
)))
576 (setq fs-ord
(mapcar #'cdr
(cdr fs-ord
))) ; Lispify fs-ord
577 (setq fs-ord
(cons (totient-from-factors fs-ord
) fs-ord
)) ) ; totient resp. order in general
578 (gf-merror (intl:gettext
579 "Fourth argument to `zn_log' must be of the form [[p1, e1], ..., [pk, ek]]." )))
580 (let (($intfaclim
) (ord ($zn_order g n
)))
581 (setq fs-ord
(cons ord
(get-factor-list ord
))) ))
583 ((= 0 (mod (- a
(* g g
)) n
))
585 ((= 1 (mod (* a g
) n
))
586 (mod -
1 (car fs-ord
)) )
589 (car fs-ord
) ;; order
590 (cdr fs-ord
) ) ))))) ;; factors with multiplicity
592 ;; Pohlig-Hellman-reduction:
594 ;; Solve g^x = a mod n.
595 ;; Assume, that a is an element of (Z/nZ)*
596 ;; and g is a generator of (Z/nZ)* or of a subgroup containing a.
598 (defun zn-dlog (a g n ord fs-ord
)
599 (let (p e ord
/p om xp xk mods dlogs
(g-inv (inv-mod g n
)))
601 (setq p
(car f
) e
(cadr f
)
602 ord
/p
(truncate ord p
)
603 om
(power-mod g ord
/p n
) ;; om is a generator of prime order p
605 ;; Let op = ord/p^e, gp = g^op (mod n), ap = a^op (mod n) and
607 ;; gp is of order p^e and therefore
608 ;; (*) gp^xp = ap (mod n).
609 (do ((b a
) (k 0) (pk 1) (acc g-inv
) (e1 (1- e
))) (()) ;; Solve (*) by solving e logs ..
610 (setq xk
(dlog-rho (power-mod b ord
/p n
) om p n
)) ;; .. in subgroups of order p.
613 (when (= k e
) (return)) ;; => xp = x_0+x_1*p+x_2*p^2+...+x_{e-1}*p^{e-1} < p^e
614 (setq ord
/p
(truncate ord
/p p
)
616 (when (/= xk
0) (setq b
(mod (* b
(power-mod acc xk n
)) n
)))
617 (when (/= k e1
) (setq acc
(power-mod acc p n
))) )
618 (push (expt p e
) mods
)
620 (car (solve-congruences dlogs mods
)) )) ;; Find x (mod ord) with x = xp (mod p^e) for all p,e.
622 ;; baby-steps-giant-steps:
624 (defun dlog-baby-giant (a g p n
) ;; g is generator of order p mod n
625 (let* ((m (1+ (isqrt p
)))
626 (s (floor (* 1.3 m
)))
630 (make-hash-table :size s
:test
#'eql
:rehash-threshold
0.9) )
635 (return-from dlog-baby-giant r
) )
636 (setf (gethash b babies
) r
)
638 (when (= r m
) (return))
639 (setq b
(mod (* gi b
) n
)) )
640 (setq g^m
(power-mod g m n
))
642 (bb 1 (mod (* g^m bb
) n
))
644 (when (setq r
(gethash bb babies
))
646 (return (+ (* rr m
) r
)) )) ))
650 (defun dlog-naive (a g n
)
651 (do ((i 0 (1+ i
)) (gi 1 (mod (* gi g
) n
)))
654 ;; Pollard rho for dlog computation (Brents variant of collision detection)
656 (defun dlog-rho (a g p n
) ;; g is generator of prime order p mod n
660 ((= 0 (mod (- a
(* g g
)) n
)) 2)
661 ((= 1 (mod (* a g
) n
)) (1- p
))
662 ((< p
512) (dlog-naive a g n
))
663 ((< p
65536) (dlog-baby-giant a g p n
))
665 (prog ((b 1) (y 0) (z 0) ;; b = g^y * a^z
666 (bb 1) (yy 0) (zz 0) ;; bb = g^yy * a^zz
669 (do ((i 0)(j 1)) (()) (declare (fixnum i j
))
670 (multiple-value-setq (b y z
) (dlog-f b y z a g p n
))
671 (when (equal b bb
) (return)) ;; g^y * a^z = g^yy * a^zz
674 (setq j
(1+ (ash j
1)))
675 (setq bb b yy y zz z
) ))
676 (setq dy
(mod (- y yy
) p
) dz
(mod (- zz z
) p
)) ;; g^dy = a^dz = g^(x*dz)
677 (when (= 1 (gcd dz p
))
678 (return (zn-quo dy dz p
)) ) ;; x = dy/dz mod p (since g is generator of order p)
682 yy
(1+ (random (1- p
)))
683 zz
(1+ (random (1- p
)))
684 bb
(mod (* (power-mod g yy n
) (power-mod a zz n
)) n
) )
687 ;; iteration for Pollard rho: b = g^y * a^z in each step
689 (defun dlog-f (b y z a g ord n
)
693 (values (mod (* b b
) n
) (mod (ash y
1) ord
) (mod (ash z
1) ord
)) )
694 ((= 1 m
) ;; avoid stationary case b=1 => b*b=1
695 (values (mod (* a b
) n
) y
(mod (+ z
1) ord
) ) )
697 (values (mod (* g b
) n
) (mod (+ y
1) ord
) z
) ) )))
700 ;; characteristic factors:
702 (defmfun $zn_characteristic_factors
(m)
703 (unless (and (integerp m
) (> m
1)) ;; according to Shanks no result for m = 1
704 (gf-merror (intl:gettext
705 "`zn_characteristic_factors': Argument must be an integer greater than 1." )))
706 (cons '(mlist simp
) (zn-characteristic-factors m
)) )
708 (defmfun $zn_carmichael_lambda
(m)
711 (if (= m
1) 1 (zn-characteristic-factors m t
)) )
712 (t (gf-merror (intl:gettext
713 "`zn_carmichael_lambda': Argument must be a positive integer." )))))
715 ;; D. Shanks - Solved and unsolved problems in number theory, 2. ed
716 ;; definition 29 and 30 (p. 92 - 94)
718 ;; (zn-characteristic-factors 104) --> (2 2 12)
719 ;; => Z104* is isomorphic to M2 x M2 x M12
720 ;; the direct product of modulo multiplication groups of order 2 resp. 12
722 (defun zn-characteristic-factors (m &optional lambda-only
) ;; m > 1
724 (pe-list (get-factor-list m
)) ;; def. 29 part A
725 (shanks-phi ;; part D
727 (apply #'nconc
(mapcar #'zn-shanks-phi-step-bc pe-list
))
730 (do ((todo shanks-phi
(nreverse left
))
731 (p 0 0) (f 1 1) (left nil nil
)
735 (setq q
(car qd
) d
(cadr qd
))
738 (setq p q f
(* f
(expt q d
))) ))
739 (when lambda-only
(return-from zn-characteristic-factors f
))
742 ;; definition 29 parts B,C (p. 92)
743 (defun zn-shanks-phi-step-bc (pe)
744 (let ((p (car pe
)) (e (cadr pe
)) qd
)
747 (setq qd
(list (if (> e
1) '(2 1) '(1 1))))
748 (when (> e
2) (setq qd
(nconc qd
(list `(2 ,(- e
2)))))) )
750 (setq qd
(let (($intfaclim
)) (get-factor-list (1- p
))))
752 (setq qd
(nconc qd
(list `(,p
,(1- e
))))) )))
756 (cond ((> (car a
) (car b
)) t
)
757 ((< (car a
) (car b
)) nil
)
758 (t (> (cadr a
) (cadr b
))) ))
761 ;; factor generators:
763 (defmfun $zn_factor_generators
(m)
764 (unless (and (integerp m
) (> m
1))
765 (gf-merror (intl:gettext
766 "`zn_factor_generators': Argument must be an integer greater or equal 2." )))
767 (cons '(mlist simp
) (zn-factor-generators m
)) )
769 ;; D. Shanks - Solved and unsolved problems in number theory, 2. ed
770 ;; Theorem 44, page 94
772 ;; zn_factor_generators(104); --> [79,27,89]
773 ;; zn_characteristic_factors(104); --> [2,2,12]
774 ;; map(lambda([g], zn_order(g,104)), [79,27,89]); --> [2,2,12]
776 ;; Every element in Z104* can be expressed as
777 ;; 79^i * 27^j * 89^k (mod m) where 0 <= i,j < 2 and 0 <= k < 12
779 ;; The proof of theorem 44 contains the construction of the factor generators.
781 (defun zn-factor-generators (m) ;; m > 1
783 (fs (sort (get-factor-list m
) #'< :key
#'car
))
785 (p (car pe
)) (e (cadr pe
))
787 phi fs-phi ga gs ords fs-ords pegs
)
788 ;; lemma 1, page 98 :
789 ;; (Z/mZ)* is cyclic when m =
791 (return-from zn-factor-generators
(list 1)) )
792 (when (or (< m
8) ;; 3,4,5,6,7
793 (and (> p
2) (null (cdr fs
))) ;; p^k, p#2
794 (and (= 2 p
) (= 1 e
) (null (cddr fs
))) ) ;; 2*p^k, p#2
795 (setq phi
(totient-by-fs-n fs
)
796 fs-phi
(sort (mapcar #'car
(get-factor-list phi
)) #'<)
797 ga
(zn-primroot m phi fs-phi
) )
798 (return-from zn-factor-generators
(list ga
)) )
802 (unless (and (= e
1) (cdr fs
)) ;; phi(2*m) = phi(m) if m#1 is odd
803 (push (1- a
) gs
) ) ;; a = 2^e
804 (when (> e
1) (setq ords
(list 2) fs-ords
(list '((2 1)))))
806 (push 3 gs
) (push (expt 2 (- e
2)) ords
) (push `((2 ,(- e
2))) fs-ords
) ))
807 ;; lemma 2, page 100 :
809 (setq phi
(* (1- p
) (expt p
(1- e
)))
810 fs-phi
(sort (get-factor-list (1- p
)) #'< :key
#'car
) )
811 (when (> e
1) (setq fs-phi
(nconc fs-phi
(list `(,p
,(1- e
))))))
812 (setq ga
(zn-primroot a phi
(mapcar #'car fs-phi
)) ;; factors only
815 fs-ords
(list fs-phi
) )))
819 (setq pe
(car fs
) fs
(cdr fs
)
820 p
(car pe
) e
(cadr pe
)
821 phi
(* (1- p
) (expt p
(1- e
)))
822 fs-phi
(sort (get-factor-list (1- p
)) #'< :key
#'car
) )
823 (when (> e
1) (setq fs-phi
(nconc fs-phi
(list `(,p
,(1- e
))))))
825 gb
(zn-primroot b phi
(mapcar #'car fs-phi
))
826 c
(mod (* (inv-mod b a
) (- 1 gb
)) a
) ;; CRT: h = gb mod b
827 h
(+ (* b c
) gb
) ;; CRT: h = 1 mod a
829 gs
(mapcar #'(lambda (g) (+ (* a
(mod (* ia
(- 1 g
)) b
)) g
)) gs
)
832 fs-ords
(cons fs-phi fs-ords
)
834 ;; lemma 3, page 101 :
836 (mapcar #'(lambda (g ord f
)
837 (mapcar #'(lambda (pe)
839 (list (power-mod g
(truncate ord
(apply #'expt pe
)) m
)) ))
842 (setq pegs
(sort (apply #'append pegs
) #'zn-pe
>))
843 (do ((todo pegs
(nreverse left
))
844 (q 0 0) (fg 1 1) (left nil nil
)
848 (setq p
(car peg
) g
(caddr peg
))
851 (setq q p fg
(mod (* fg g
) m
)) ))
855 ;; r-th roots --------------------------------------------------------------- ;;
857 ;; If the residue class a is an r-th power modulo n and contained in a multiplication
858 ;; subgroup of (Z/nZ), return all r-th roots from this subgroup and false otherwise.
860 (defmfun $zn_nth_root
(a r n
&optional fs-n
)
861 (unless (and (integerp a
) (integerp r
) (integerp n
))
862 (gf-merror (intl:gettext
863 "`zn_nth_root' needs three integer arguments. Found ~m, ~m, ~m." ) a r n
))
864 (unless (and (> r
0) (> n
0))
865 (gf-merror (intl:gettext
866 "`zn_nth_root': Second and third arg must be pos integers. Found ~m, ~m." ) r n
))
868 (if (and ($listp fs-n
) ($listp
(cadr fs-n
)))
869 (setq fs-n
(mapcar #'cdr
(cdr fs-n
))) ;; Lispify fs-n
870 (gf-merror (intl:gettext
871 "`zn_nth_root': The opt fourth arg must be of the form [[p1, e1], ..., [pk, ek]]." ))))
872 (let ((rts (zn-nrt a r n fs-n
)))
873 (when rts
(cons '(mlist simp
) rts
)) ))
875 (defun zn-nrt (a r n
&optional fs-n
)
876 (let (g n
/g c p q aq ro ord qs rt rts rems res
)
877 (unless fs-n
(setq fs-n
(let (($intfaclim
)) (get-factor-list n
))))
880 ((every #'onep
(mapcar #'second fs-n
)) ;; RSA-like case (n is squarefree)
881 (when (= a
0) (return-from zn-nrt
(list 0))) ) ;; n = 1: exit here
883 ;; Handle residue classes not coprime to n (n is not squarefree):
884 ;; Use Theorems 49 and 50 from
885 ;; Shanks - Solved and Unsolved Problems in Number Theory
886 (setq g
(gcd a n
) n
/g
(truncate n g
))
887 (when (/= (gcd g n
/g
) 1) ;; a is not contained in any mult. subgroup (Th. 50):
888 (return-from zn-nrt nil
) ) ;; exit here
889 (when (= a
0) (return-from zn-nrt
(list 0)))
890 ;; g = gcd(a,n). Now assume gcd(g,n/g) = 1.
891 ;; There are totient(n/g) multiples of g, i*g, with gcd(i,n/g) = 1,
892 ;; which form a modulo multiplication subgroup of (Z/nZ),
893 ;; isomorphic to (Z/mZ)*, where m = n/g.
894 ;; a is one of these multiples of g.
895 ;; Find the r-th roots of a resp. mod(a,m) in (Z/mZ)* and then
896 ;; by using CRT all corresponding r-th roots of a in (Z/nZ).
899 c
(inv-mod g n
/g
) ;; CRT-coeff
900 ;; isomorphic mapping (Th. 49):
901 ;; (use CRT with x = 0 mod g and x = rt mod n/g)
902 res
(mapcar #'(lambda (rt) (* g
(mod (* c rt
) n
/g
))) rts
) )
903 (return-from zn-nrt
(sort res
#'<)) ))
905 ;; for every prime power factor of n
906 ;; reduce a and r if possible and call zq-nrt:
911 ord
(* (1- p
) (truncate q p
)) )
914 (setq ro
(mod r ord
))
915 (when (= ro
0) (setq ro ord
)) )
919 (if (or (= p q
) (= ro
1))
921 (return-from zn-nrt nil
) ))
923 (setq rt
(list aq
)) )
925 (setq rt
(zq-nrt aq ro p q
))
926 (unless rt
(return-from zn-nrt nil
)) ))
929 ;; CRT in case n splits into more than one factor:
930 (if (= 1 (length fs-n
))
931 (setq res rt
) ;; n is a prime power
932 (setq qs
(nreverse qs
)
933 rems
(zn-distrib-lists (nreverse rts
))
934 res
(mapcar #'(lambda (rs) (car (solve-congruences rs qs
))) rems
) ))
937 ;; return all possible combinations containing one entry per list:
938 ;; (zn-distrib-lists '((1 2 3) (4) (5 6)))
939 ;; --> ((1 4 5) (1 4 6) (2 4 5) (2 4 6) (3 4 5) (3 4 6))
941 (defun zn-distrib-lists (ll)
942 (let ((res (car ll
)) tmp e
)
943 (dolist (l (cdr ll
) res
)
947 (setq e
(if (listp r
) (copy-list r
) (list r
)))
948 (push (nconc e
(list n
)) tmp
) ))
949 (setq res
(nreverse tmp
)) )))
951 ;; handle composite r (which are not coprime to totient(q)):
952 ;; e.g. r=x*x*y*z, then a^(1/r) = (((a^(1/x))^(1/x))^(1/y))^(1/z)
954 (defun zq-nrt (a r p q
) ;; prime power q = p^e
955 ;; assume a < q, r <= q
958 ((or (= 1 r
) (primep r
))
959 (setq rts
(zq-amm a r p q
)) )
960 ((and (= (gcd r
(1- p
)) 1) (or (= p q
) (= (gcd r p
) 1))) ;; r is coprime to totient(q):
961 (let ((ord (* (1- p
) (truncate q p
))))
962 (setq rts
(list (power-mod a
(inv-mod r ord
) q
))) )) ;; unique solution
964 (let* (($intfaclim
) (rs (get-factor-list r
)))
965 (setq rs
(sort rs
#'< :key
#'car
))
969 #'(lambda (pe) (apply #'(lambda (p e
) (make-list e
:initial-element p
)) pe
))
971 (setq rts
(zq-amm a
(car rs
) p q
))
973 (setq rts
(apply #'nconc
(mapcar #'(lambda (a) (zq-amm a r p q
)) rts
))) ))))
974 (if (and (= p
2) (> q
2) (evenp r
)) ;; this case needs a postprocess (see below)
975 (nconc (mapcar #'(lambda (rt) (- q rt
)) rts
) rts
) ;; add negative solutions
978 ;; Computing r-th roots modulo a prime power p^n, where r is a prime
981 ;; Bach,Shallit - Algorithmic Number Theory, Theorem 7.3.2
983 ;; Shanks - Solved and Unsolved Problems in Number Theory, Th. 46, Lemma 1 to Th. 44
985 ;; The algorithm AMM (Adleman, Manders, Miller) is essentially based on
986 ;; properties of cyclic groups and with the exception of q = 2^n, n > 2
987 ;; it can be applied to any multiplicative group (Z/qZ)* where q = p^n.
989 ;; Doing so, the order q-1 of Fq* in Th. 7.3.2 has to be replaced by the
990 ;; group order totient(q) of (Z/qZ)*.
992 ;; But how to include q = 8,16,32,... ?
993 ;; r > 2: r is prime. There exists a unique solution for all a in (Z/qZ)*.
994 ;; r = 2 (the square root case):
995 ;; - (Z/qZ)* has k = 2 characteristic factors [2,q/4] with [-1,3] as possible
996 ;; factor generators (see Shanks, Lemma 1 to Th. 44).
997 ;; I.e. 3 is of order q/4 and 3^2 = 9 of order q/8.
998 ;; - (Z/qZ)* has totient/2^k = q/8 quadratic residues with 2^k = 4 roots each
999 ;; (see Shanks, Th. 46).
1000 ;; - It follows that the subgroup <3> generated by 3 contains all quadratic
1001 ;; residues of (Z/qZ)* (which must be all the powers of 9 located in <3>).
1002 ;; - We apply the algorithm AMM for cyclic groups to <3> and compute two
1003 ;; square roots x,y.
1004 ;; - The numbers -x and -y, obviously roots as well, both lie in (-1)*<3>
1005 ;; and therefore they differ from x,y and complete the set of 4 roots.
1007 (defun zq-amm (a r p q
) ;; r,p prime, q = p^n
1008 ;; assume a < q, r <= q
1011 ((= 2 q
) (when (= 1 a
) (list 1)))
1012 ((= 4 q
) (when (or (= 1 a
) (and (= 3 a
) (oddp r
))) (list a
)))
1014 (let ((ord (* (1- p
) (truncate q p
))) ;; group order: totient(q)
1018 (when (/= 1 (mod a
8)) (return-from zq-amm nil
)) ;; a must be a power of 9
1020 ((/= 1 ($jacobi
(mod a p
) p
))
1021 (return-from zq-amm nil
) )
1023 (setq rt
(power-mod a
(ash (+ ord
2) -
2) q
))
1024 (return-from zq-amm
`(,rt
,(- q rt
))) )
1025 ((and (= p q
) (= 5 (mod p
8)))
1026 (let* ((x (ash a
1))
1027 (y (power-mod x
(ash (- p
5) -
3) p
))
1028 (i (mod (* x y y
) p
))
1029 (rt (mod (* a y
(1- i
)) p
)) )
1030 (return-from zq-amm
`(,rt
,(- p rt
))) )))))
1031 (when (= 2 p
) ;; q = 8,16,32,..
1032 (setq ord
(ash ord -
1)) ) ;; factor generator 3 is of order ord/2
1033 (multiple-value-setq (s m
) (truncate ord r
))
1034 (when (and (= 0 m
) (/= 1 (power-mod a s q
))) (return-from zq-amm nil
))
1035 ;; r = 3, first 2 cases:
1038 ((= 1 (setq m
(mod ord
3))) ;; unique solution
1040 `(,(power-mod a
(truncate (1+ (ash ord
1)) 3) q
)) ))
1041 ((= 2 m
) ;; unique solution
1043 `(,(power-mod a
(truncate (1+ ord
) 3) q
)) ))))
1044 ;; compute u,e with ord = u*r^e and r,u coprime:
1047 (multiple-value-setq (u1 m
) (truncate u1 r
))
1048 (when (/= 0 m
) (return))
1049 (setq u u1 e
(1+ e
)) )
1052 (setq rt
(power-mod a
(inv-mod r u
) q
)) ;; unique solution, see Bach,Shallit 7.3.1
1054 (t ;; a is an r-th power
1056 ;; find generator of order r^e:
1057 (if (= p
2) ;; p = 2: then r = 2 (other r: e = 0)
1059 (do ((n 2 ($next_prime n
)))
1060 ((and (= 1 (gcd n q
)) (/= 1 (power-mod n s q
))) ;; n is no r-th power
1061 (setq g
(power-mod n u q
)) )))
1063 om
(power-mod g
(truncate re r
) q
) ) ;; r-th root of unity
1065 ((or (/= 3 r
) (= 0 (setq m
(mod ord
9))))
1066 (let (ar au br bu k ab alpha beta
)
1067 ;; map a from Zq* to C_{r^e} x C_u:
1068 (setq ar
(power-mod a u q
) ;; in C_{r^e}
1069 au
(power-mod a re q
) ) ;; in C_u
1070 ;; compute direct factors of rt:
1071 ;; (the loop in algorithm AMM is effectively a Pohlig-Hellman-reduction, equivalent to zn-dlog)
1072 (setq k
(zn-dlog ar g q re
`((,r
,e
))) ;; g^k = ar, where r|k
1073 br
(power-mod g
(truncate k r
) q
) ;; br^r = g^k (factor of rt in C_{r^e})
1074 bu
(power-mod au
(inv-mod r u
) q
) ) ;; bu^r = au (factor of rt in C_u)
1075 ;; mapping from C_{r^e} x C_u back to Zq*:
1076 (setq ab
(cdr (zn-gcdex1 u re
))
1079 (if (< alpha
0) (incf alpha ord
) (incf beta ord
))
1080 (setq rt
(mod (* (power-mod br alpha q
) (power-mod bu beta q
)) q
)) ))
1081 ;; r = 3, remaining cases:
1083 (setq rt
(power-mod a
(truncate (+ (ash ord
1) 3) 9) q
)) )
1085 (setq rt
(power-mod a
(truncate (+ ord
3) 9) q
)) ))
1086 ;; mult with r-th roots of unity:
1087 (do ((i 1 (1+ i
)) (j 1) (res (list rt
)))
1089 (setq j
(mod (* j om
) q
))
1090 (push (mod (* rt j
) q
) res
) ))))))))
1092 ;; -------------------------------------------------------------------------- ;;
1095 ;; Two variants of gcdex:
1097 ;; returns gcd as first entry:
1098 ;; (zn-gcdex1 12 45) --> (3 4 -1), so 4*12 + -1*45 = 3
1099 (defun zn-gcdex1 (x y
)
1100 (let ((x1 1) (x2 0) (y1 0) (y2 1) q r
)
1101 (do ()((= 0 y
) (list x x1 x2
))
1102 (multiple-value-setq (q r
) (truncate x y
))
1104 (psetf x1 y1 y1
(- x1
(* q y1
)))
1105 (psetf x2 y2 y2
(- x2
(* q y2
))) )))
1107 ;; returns gcd as last entry:
1108 ;; (zn-gcdex 12 45 21) --> (4 -1 0 3), so 4*12 + -1*45 + 0*21 = 3
1109 (defun zn-gcdex (&rest args
)
1110 (let* ((ex (zn-gcdex1 (car args
) (cadr args
)))
1113 (dolist (a (cddr args
) (nconc cs
(list g
)))
1114 (setq ex
(zn-gcdex1 g a
)
1118 cs
(nconc (mapcar #'(lambda (c) (* c c1
)) cs
) (cdr ex
)) ))))
1121 ;; for educational purposes: tables of small residue class rings
1123 (defun zn-table-errchk (n fun
)
1124 (unless (and (fixnump n
) (< 1 n
))
1125 (gf-merror (intl:gettext
1126 "Argument to `~m' must be a small fixnum greater than 1." ) fun
)))
1128 (defmfun $zn_add_table
(n)
1129 (zn-table-errchk n
"zn_add_table")
1130 (do ((i 0 (1+ i
)) res
)
1132 (cons '($matrix simp
) (nreverse res
)) )
1133 (push (mfuncall '$makelist
`((mod) (+ ,i $j
) ,n
) '$j
0 (1- n
)) res
) ))
1135 ;; multiplication table modulo n
1137 ;; The optional g allows to choose subsets of (Z/nZ). Show i with gcd(i,n) = g resp. all i#0.
1138 ;; If n # 1 add row and column headings for better readability.
1140 (defmfun $zn_mult_table
(n &optional g
)
1141 (zn-table-errchk n
"zn_mult_table")
1142 (let ((i0 1) all header choice res
)
1144 ((not g
) (setq g
1))
1145 ((equal g
'$all
) (setq all t
))
1147 (gf-merror (intl:gettext
1148 "`zn_mult_table': The opt second arg must be `all' or a small fixnum." )))
1150 (when (= n g
) (setq i0
0))
1151 (push 1 choice
) ;; creates the headers
1155 (setq choice
(cons '(mlist simp
) (nreverse choice
))) )
1156 (when (or all
(= g
(gcd i n
))) (push i choice
)) )
1157 (when (and header
(= (length choice
) 2))
1158 (return-from $zn_mult_table
) )
1159 (dolist (i (cdr choice
))
1160 (push (mfuncall '$makelist
`((mod) (* ,i $j
) ,n
) '$j choice
) res
) )
1161 (setq res
(nreverse res
))
1162 (when header
(rplaca (cdar res
) "*"))
1163 (cons '($matrix simp
) res
) ))
1165 ;; power table modulo n
1167 ;; The optional g allows to choose subsets of (Z/nZ). Show i with gcd(i,n) = g resp. all i.
1169 (defmfun $zn_power_table
(n &optional g e
)
1170 (zn-table-errchk n
"zn_power_table")
1173 ((not g
) (setq g
1))
1174 ((equal g
'$all
) (setq all t
))
1176 (gf-merror (intl:gettext
1177 "`zn_power_table': The opt second arg must be `all' or a small fixnum." ))))
1179 ((not e
) (setq e
(zn-characteristic-factors n t
)))
1181 (gf-merror (intl:gettext
1182 "`zn_power_table': The opt third arg must be a small fixnum." ))))
1183 (do ((i 0 (1+ i
)) res
)
1185 (when res
(cons '($matrix simp
) (nreverse res
))) )
1186 (when (or all
(= g
(gcd i n
)))
1187 (push (mfuncall '$makelist
`((power-mod) ,i $j
,n
) '$j
1 e
) res
) ))))
1190 ;; $zn_invert_by_lu (m p)
1191 ;; $zn_determinant (m p)
1192 ;; see below: --> galois fields--> interfaces to linearalgebra/lu.lisp
1195 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1198 ;; -----------------------------------------------------------------------------
1199 ;; *** GALOIS FIELDS ***
1201 ;; The following is a revision and improvement of the first part of share/
1202 ;; contrib/gf/gf.mac by Alasdair McAndrew, Fabrizio Caruso and Jacopo D'Aurizio
1203 ;; released under terms of the GPLv2 in 2007.
1205 ;; I would like to thank the original authors for their contribution to Maxima
1206 ;; which allowed me to study, improve and extend the source code.
1208 ;; I would also like to thank Camm Maguire who helped me coding compiler macros
1211 ;; 2012 - 2014, Volker van Nek
1213 (declare-top (special *gf-char
* *gf-exp
* *ef-arith?
*)) ;; modulus $intfaclim see above
1215 (defvar *gf-rat-header
* nil
"header of internal CRE representation")
1217 (defvar *ef-arith?
* nil
"Should extension field arithmetic be used?")
1220 (defvar *gf-char
* 0 "characteristic p")
1221 (defvar *gf-exp
* 0 "exponent n, degree of the reduction polynomial")
1222 (defvar *gf-ord
* 0 "group order, number of units")
1223 (defvar *gf-card
* 0 "cardinality, ring order")
1224 (defvar *gf-red
* nil
"reduction polynomial")
1225 (defvar *gf-prim
* nil
"primitive element")
1226 (defvar *gf-fs-ord
* nil
"ifactors of *gf-ord*")
1227 (defvar *gf-fsx
* nil
"extended factors of *gf-ord*")
1228 (defvar *gf-fsx-base-p
* nil
"*gf-fsx* in base p")
1229 (defvar *gf-x^p-powers
* nil
"x^p^i, i=0,..,n-1")
1231 (defvar *f2-red
* 0 "reduction polynomial") ;; used by ef coeff arith over binary fields
1233 (declaim (fixnum *gf-exp
* *ef-exp
*))
1236 (defvar *ef-exp
* 0 "exponent m, degree of the reduction polynomial")
1237 (defvar *ef-ord
* 0 "group order, number of units")
1238 (defvar *ef-card
* 0 "cardinality, ring order")
1239 (defvar *ef-red
* nil
"reduction polynomial")
1240 (defvar *ef-prim
* nil
"primitive element")
1241 (defvar *ef-fs-ord
* nil
"ifactors of *ef-ord*")
1242 (defvar *ef-fsx
* nil
"extended factors of *ef-ord*")
1243 (defvar *ef-fsx-base-q
* nil
"*ef-fsx* in base q = p^n")
1244 (defvar *ef-x^q-powers
* nil
"x^q^i, i=0,..,m-1")
1246 (defvar *gf-char?
* nil
"Was the characteristic defined?")
1247 (defvar *gf-red?
* nil
"Was the reduction polynomial defined?")
1248 (defvar *gf-irred?
* nil
"Is the reduction polynomial irreducible?")
1249 (defvar *gf-data?
* nil
"gf_set_data called?")
1251 (defvar *ef-red?
* nil
"Was the reduction polynomial defined?")
1252 (defvar *ef-irred?
* nil
"Is the reduction polynomial irreducible?")
1253 (defvar *ef-data?
* nil
"ef_set_data called?")
1255 (defmvar $gf_rat nil
"Return values are rational expressions?" boolean
)
1257 (defmvar $gf_symmetric nil
"A symmetric modulus should be used?" boolean
) ;; deprecated
1258 (defmvar $gf_balanced nil
"A balanced modulus should be used?" boolean
) ;; there is ec_balanced in elliptic_curves.lisp
1260 (putprop '$gf_symmetric
'gf-balanced-info
'assign
)
1262 (defun gf-balanced-info (assign-var arg
)
1263 (declare (ignore assign-var
))
1264 (setq $gf_balanced arg
)
1265 (format t
"`gf_symmetric' is deprecated and replaced by `gf_balanced'.~%The value is bound to `gf_balanced'.") )
1266 ;; temporarily print this message
1269 (defmvar $gf_coeff_limit
256
1270 "`gf_coeff_limit' limits the coeffs when searching for irreducible and primitive polynomials." fixnum
)
1272 (putprop '$gf_coeff_limit
'gf-coeff-check
'assign
)
1274 (defun gf-coeff-check (assign-var arg
)
1275 (declare (ignore assign-var
))
1276 (unless (and (integerp arg
) (> arg
1))
1277 (gf-merror (intl:gettext
1278 "`gf_coeff_limit': Assignment ignored. Value must be an integer greater than 1.~%" ))))
1280 (defmvar $gf_cantor_zassenhaus t
"Should the Cantor-Zassenhaus algorithm be used?" boolean
)
1282 (defmvar $ef_coeff_mult nil
)
1283 (defmvar $ef_coeff_add nil
)
1284 (defmvar $ef_coeff_inv nil
)
1285 (defmvar $ef_coeff_exp nil
)
1287 (defmvar $gf_powers nil
)
1288 (defmvar $gf_logs nil
)
1289 (defmvar $gf_zech_logs nil
)
1290 (defvar *gf-powers
* nil
"alpha^i, i=0,..,ord-1 where alpha is a primitive element")
1291 (defvar *gf-logs?
* nil
"Were the power and log tables calculated?")
1294 ;; contains parts of merror.lisp/merror but avoids "To debug this ...".
1296 (defun gf-merror (sstring &rest l
)
1297 (setq $error
`((mlist) ,sstring
,@ l
))
1298 (and $errormsg
($errormsg
))
1299 (fresh-line *standard-output
*)
1300 (format t
(intl:gettext
"~& -- an error.~%"))
1301 (throw 'macsyma-quit
'maxima-error
) )
1304 (defun gf-char?
(fun)
1306 (gf-merror (intl:gettext
"`~m': The characteristic is not defined yet.") fun
) ))
1308 (defun gf-red?
(fun)
1310 (gf-merror (intl:gettext
"`~m': The reduction polynomial is not defined yet.") fun
) ))
1312 (defun gf-data?
(fun)
1314 (gf-merror (intl:gettext
"`~m': gf_set_data called?") fun
) ))
1316 (defun gf-field?
(fun)
1317 (if (and (gf-data? fun
) *gf-irred?
*) t
1318 (gf-merror (intl:gettext
"`~m': The reduction polynomial is not irreducible.") fun
) ))
1321 (defun ef-gf-field?
(fun)
1322 (if (and *gf-data?
* *gf-irred?
*) t
1323 (gf-merror (intl:gettext
"`~m': The base field is not defined yet.") fun
) ))
1325 (defun ef-red?
(fun)
1326 (if (and (ef-gf-field? fun
) *ef-red?
*) t
1327 (gf-merror (intl:gettext
"`~m': The reduction polynomial is not defined yet.") fun
) ))
1329 (defun ef-data?
(fun)
1330 (if (and (ef-gf-field? fun
) *ef-data?
*) t
1331 (gf-merror (intl:gettext
"`~m': ef_set_data called?") fun
) ))
1333 (defun ef-field?
(fun)
1334 (if (and (ef-data? fun
) *ef-irred?
*) t
1335 (gf-merror (intl:gettext
"`~m': The extension is no field.") fun
) ))
1337 ;; -----------------------------------------------------------------------------
1340 ;; basic coefficient arithmetic ------------------------------------------------
1343 ;; optimize the fixnum cases
1345 (defmacro maybe-char-is-fixnum-let
(binds &body body
)
1346 `(if (or (and (not *ef-arith?
*) (typep *gf-char
* 'fixnum
))
1347 (and *ef-arith?
* (typep *gf-card
* 'fixnum
)) )
1349 (declare (fixnum ,@(mapcar #'(lambda (x) (car x
)) binds
)))
1352 (declare (integer ,@(mapcar #'(lambda (x) (car x
)) binds
)))
1355 ;; basic coefficient functions and compiler macros
1357 ;; gf coefficient arith :
1359 ;; *ef-arith?* controls coefficient arithmetic. If *ef-arith?* is false,
1360 ;; coeffs are elements of Zp, where p is the defined characteristic *gf-char*.
1361 ;; If *ef-arith?* is true, coeffs are interpreted as the integer representation
1362 ;; of a polynomial over Zp[x] reduced by the irreducible polynomial *gf-red*.
1367 (maybe-char-is-fixnum-let ((c c
))
1369 ((= 0 c
) (gf-merror (intl:gettext
"gf coefficient inversion: Quotient by zero")))
1370 (t (inv-mod c
*gf-char
*)) )))) ; *gf-char* is prime
1372 (defun gf-cpow (c n
)
1375 (maybe-char-is-fixnum-let ((c c
))
1376 (power-mod c n
*gf-char
*) )))
1381 (maybe-char-is-fixnum-let ((c c
))
1382 (mod c
*gf-char
*) )))
1384 (defun gf-ctimes (a b
)
1387 (maybe-char-is-fixnum-let ((a a
)(b b
))
1388 (mod (* a b
) *gf-char
*) )))
1390 (defun gf-cplus-b (a b
) ;; assumes that both 0 <= a,b < *gf-char*
1392 (*ef-arith?
* (ef-cplus-b a b
))
1393 (t (maybe-char-is-fixnum-let ((a a
)(b b
))
1395 (if (< (the integer s
) *gf-char
*)
1397 (- (the integer s
) *gf-char
*) ))))))
1399 (defun gf-cminus-b (c) ;; assumes that 0 <= c < *gf-char*
1403 (*ef-arith?
* (ef-cminus-b c
))
1404 (t (maybe-char-is-fixnum-let ((c c
))
1405 (- *gf-char
* c
) ))))
1407 ;; ef coefficient arith :
1410 (declare (integer c
))
1412 ((= 0 c
) (gf-merror (intl:gettext
"ef coefficient inversion: Quotient by zero")))
1413 ($ef_coeff_inv
(mfuncall '$ef_coeff_inv c
))
1414 (*gf-logs?
* (ef-cinv-by-table c
))
1415 ((= 2 *gf-char
*) (f2-inv c
))
1416 (t (let ((*ef-arith?
*))
1417 (gf-x2n (gf-inv (gf-n2x c
) *gf-red
*)) ))))
1419 (defun ef-cpow (c n
)
1421 ($ef_coeff_exp
(mfuncall '$ef_coeff_exp c n
))
1422 (*gf-logs?
* (ef-cpow-by-table c n
))
1423 ((= 2 *gf-char
*) (f2-pow c n
))
1424 (t (let ((*ef-arith?
*))
1425 (gf-x2n (gf-pow (gf-n2x c
) n
*gf-red
*)) ))))
1428 (declare (integer c
))
1433 ((= 2 *gf-char
*) (f2-red c
))
1434 (t (let ((*ef-arith?
*))
1435 (gf-x2n (gf-nred (gf-n2x c
) *gf-red
*)) ))))
1437 (setq c
(ef-cmod (abs c
)))
1438 (let ((*ef-arith?
* t
)) (gf-ctimes (1- *gf-char
*) c
)) )))
1440 (defun ef-ctimes (a b
)
1442 ($ef_coeff_mult
(mfuncall '$ef_coeff_mult a b
))
1443 (*gf-logs?
* (ef-ctimes-by-table a b
))
1444 ((= 2 *gf-char
*) (f2-times a b
))
1445 (t (let ((*ef-arith?
*))
1446 (gf-x2n (gf-times (gf-n2x a
) (gf-n2x b
) *gf-red
*)) ))))
1448 (defun ef-cplus-b (a b
)
1450 ((= 2 *gf-char
*) (logxor a b
))
1451 ($ef_coeff_add
(mfuncall '$ef_coeff_add a b
))
1452 (*gf-logs?
* (ef-cplus-by-table a b
))
1453 (t (let ((*ef-arith?
*))
1454 (gf-x2n (gf-nplus (gf-n2x a
) (gf-n2x b
))) ))))
1456 (defun ef-cminus-b (a)
1460 ($ef_coeff_mult
(mfuncall '$ef_coeff_mult
(1- *gf-char
*) a
))
1461 (*gf-logs?
* (ef-cminus-by-table a
))
1462 (t (let ((*ef-arith?
*))
1463 (gf-x2n (gf-nminus (gf-n2x a
))) ))))
1465 ;; ef coefficient arith by lookup:
1467 (defun ef-ctimes-by-table (c d
)
1468 (declare (fixnum c d
))
1470 ((or (= 0 c
) (= 0 d
)) 0)
1471 (t (let ((cd (+ (the fixnum
(svref $gf_logs c
))
1472 (the fixnum
(svref $gf_logs d
)) )))
1473 (svref $gf_powers
(if (< (the integer cd
) *gf-ord
*) cd
(- cd
*gf-ord
*))) ))))
1475 (defun ef-cminus-by-table (c)
1476 (declare (fixnum c
))
1480 (t (let ((e (ash *gf-ord
* -
1))) (declare (fixnum e
))
1481 (setq c
(svref $gf_logs c
))
1482 (svref $gf_powers
(the fixnum
(if (< c e
) (+ c e
) (- c e
)))) ))))
1484 (defun ef-cinv-by-table (c)
1485 (declare (fixnum c
))
1487 ((= 0 c
) (gf-merror (intl:gettext
"ef coefficient inversion: Quotient by zero")))
1488 (t (svref $gf_powers
(- *gf-ord
* (the fixnum
(svref $gf_logs c
))))) ))
1490 (defun ef-cplus-by-table (c d
)
1491 (declare (fixnum c d
))
1495 (t (setq c
(svref $gf_logs c
) d
(aref $gf_logs d
))
1496 (let ((z (svref $gf_zech_logs
(the fixnum
(if (< d c
) (+ *gf-ord
* (- d c
)) (- d c
))))))
1499 (svref $gf_powers
(the fixnum
(if (> z
*gf-ord
*) (- z
*gf-ord
*) z
))) )
1502 (defun ef-cpow-by-table (c n
)
1503 (declare (fixnum c n
))
1507 (t (svref $gf_powers
1508 (mod (* n
(the fixnum
(svref $gf_logs c
))) *gf-ord
*) )) ))
1511 (defun gf-pow-by-table (x n
) ;; table lookup uses current *gf-red* for reduction
1512 (declare (fixnum n
))
1514 ((= 0 n
) (list 0 1))
1516 (t (svref *gf-powers
*
1517 (mod (* n
(the fixnum
(svref $gf_logs
(gf-x2n x
)))) *gf-ord
*) )) ))
1520 ;; ef coefficient arith for binary base fields:
1523 (declare (optimize (speed 3) (safety 0)))
1524 (let* ((red *f2-red
*)
1525 (ilen (integer-length red
))
1527 (declare (fixnum e ilen
))
1529 (setq e
(- (integer-length a
) ilen
))
1530 (when (< e
0) (return a
))
1531 (setq a
(logxor a
(ash red e
))) )))
1533 (defun f2-times (a b
)
1534 (declare (optimize (speed 3) (safety 0)))
1535 (let* ((ilen (integer-length b
))
1536 (a1 (ash a
(1- ilen
)))
1538 (do ((i (- ilen
2) (1- i
)) (k 0))
1539 ((< i
0) (f2-red ab
))
1540 (declare (fixnum i k
))
1547 (defun f2-pow (a n
) ;; assume n >= 0
1548 (declare (optimize (speed 3) (safety 0))
1555 (setq res
(if res
(f2-times a res
) a
))
1557 (return-from f2-pow res
) ))
1559 a
(f2-times a a
)) ))))
1562 (declare (optimize (speed 3) (safety 0)))
1564 (gf-merror (intl:gettext
"f2 arithmetic: Quotient by zero")) )
1565 (let ((b1 1) (a *f2-red
*) (a1 0) q r
)
1568 (multiple-value-setq (q r
) (f2-divide a b
))
1570 (psetf a1 b1 b1
(logxor (f2-times q b1
) a1
)) )))
1572 (defun f2-divide (a b
)
1573 (declare (optimize (speed 3) (safety 0)))
1576 (gf-merror (intl:gettext
"f2 arithmetic: Quotient by zero")) )
1577 ((= a
0) (values 0 0))
1579 (let ((ilen (integer-length b
))
1582 (declare (fixnum e ilen
))
1583 (do () ((= a
0) (values q
0))
1584 (setq e
(- (integer-length a
) ilen
))
1585 (when (< e
0) (return (values q a
)))
1586 (setq q
(logxor q
(ash 1 e
)))
1587 (setq a
(logxor a
(ash b e
))) )))))
1589 ;; -------------------------------------------------------------------------- ;;
1592 #-gcl
(eval-when (:compile-toplevel
:load-toplevel
:execute
)
1594 (define-compiler-macro gf-cmod
(a)
1598 ((and (typep *gf-char
* 'fixnum
) (typep ,a
'fixnum
)) ;; maybe a > *gf-char*
1599 (let ((x ,a
) (z *gf-char
*)) (declare (fixnum x z
))
1600 (the fixnum
(mod x z
)) ))
1602 (mod (the integer
,a
) *gf-char
*) )))
1604 (define-compiler-macro gf-ctimes
(a b
)
1608 ((typep *gf-char
* 'fixnum
)
1609 (let ((x ,a
) (y ,b
) (z *gf-char
*)) (declare (fixnum x y z
))
1610 (the fixnum
(mod (* x y
) z
)) ))
1612 (mod (* (the integer
,a
) (the integer
,b
)) *gf-char
*) )))
1614 (define-compiler-macro gf-cplus-b
(a b
) ;; assumes that both 0 <= a,b < *gf-char*
1617 (ef-cplus-b ,a
,b
) )
1618 ((typep *gf-char
* 'fixnum
)
1619 (let ((x ,a
) (y ,b
) (z *gf-char
*) (s 0)) (declare (fixnum x y z
) (integer s
))
1620 (setq s
(the integer
(+ x y
)))
1621 (if (< s z
) s
(- s z
)) ))
1623 (let ((x (+ (the integer
,a
) (the integer
,b
)))) (declare (integer x
))
1624 (if (< x
*gf-char
*) x
(- x
*gf-char
*)) ))))
1626 (define-compiler-macro gf-cminus-b
(a) ;; assumes that 0 <= a < *gf-char*
1631 ((typep *gf-char
* 'fixnum
)
1632 (let ((x ,a
) (z *gf-char
*)) (declare (fixnum x z
))
1633 (the fixnum
(- z x
)) ))
1635 (- *gf-char
* (the integer
,a
)) )))
1638 #+gcl
(eval-when (compile load eval
)
1640 (push '((fixnum fixnum
) fixnum
#.
(compiler::flags compiler
::rfa
)
1641 "(fixnum)(((long long)(#0))%((long long)(#1)))" )
1642 (get 'i%
'compiler
::inline-always
) )
1643 (push '((fixnum fixnum fixnum
) fixnum
#.
(compiler::flags compiler
::rfa
)
1644 "(fixnum)((((long long)(#0))*((long long)(#1)))%((long long)(#2)))" )
1645 (get '*%
'compiler
::inline-always
) )
1646 (push '((fixnum fixnum fixnum
) fixnum
#.
(compiler::flags compiler
::rfa compiler
::set
)
1647 "@02;({long long _t=((long long)(#0))+((long long)(#1)),_w=((long long)(#2));_t<_w ? (fixnum)_t : (fixnum)(_t - _w);})" )
1648 (get '+%b
'compiler
::inline-always
) )
1649 (push '((fixnum fixnum
) fixnum
#.
(compiler::flags compiler
::rfa
)
1650 "(fixnum)(((long long)(#1))-((long long)(#0)))" )
1651 (get 'neg%b
'compiler
::inline-always
) )
1653 (setf (get 'i%
'compiler
::return-type
) t
)
1654 (setf (get '*%
'compiler
::return-type
) t
)
1655 (setf (get '+%b
'compiler
::return-type
) t
)
1656 (setf (get 'neg%b
'compiler
::return-type
) t
)
1658 (si::define-compiler-macro gf-cmod
(a)
1662 ((and (typep *gf-char
* 'fixnum
) (typep ,a
'fixnum
) (plusp ,a
)) ;; maybe a > *gf-char*
1663 (let ((x ,a
) (z *gf-char
*)) (declare (fixnum x z
))
1666 (mod (the integer
,a
) *gf-char
*) )))
1668 (si::define-compiler-macro gf-ctimes
(a b
) ;; assume that 0 <= a,b :
1673 ',(if (< (integer-length most-positive-fixnum
) 32) `fixnum
`(signed-byte 32)) )
1674 (let ((x ,a
) (y ,b
) (z *gf-char
*)) (declare (fixnum x y z
))
1677 (mod (* (the integer
,a
) (the integer
,b
)) *gf-char
*) )))
1679 (si::define-compiler-macro gf-cplus-b
(a b
) ;; assume that both 0 <= a,b < *gf-char* :
1682 (ef-cplus-b ,a
,b
) )
1684 ',(if (< (integer-length most-positive-fixnum
) 63) `fixnum
`(signed-byte 63)) )
1685 (let ((x ,a
) (y ,b
) (z *gf-char
*)) (declare (fixnum x y z
))
1688 (let ((x (+ (the integer
,a
) (the integer
,b
)))) (declare (integer x
))
1689 (if (< x
*gf-char
*) x
(- x
*gf-char
*)) ))))
1691 (si::define-compiler-macro gf-cminus-b
(a) ;; assume that 0 <= a < *gf-char* :
1696 ((typep *gf-char
* 'fixnum
)
1697 (let ((x ,a
) (z *gf-char
*)) (declare (fixnum x z
))
1700 (- *gf-char
* (the integer
,a
)) )))
1703 ;; -----------------------------------------------------------------------------
1706 ;; setting the finite field and retrieving basic information ------------------
1709 (defmfun $gf_set
(p &optional a1 a2 a3
) ;; deprecated
1710 (format t
"`gf_set' is deprecated. ~%~\
1711 The user is asked to use `gf_set_data' instead.~%" )
1713 (format t
"In future versions `gf_set_data' will only accept two arguments.~%") )
1714 ($gf_set_data p a1 a2 a3
) )
1717 (defmfun $gf_set_data
(p &optional a1 a2 a3
) ;; opt: *gf-exp*, *gf-red*, *gf-fs-ord*
1718 (declare (ignore a2 a3
)) ;; remove a2 a3 in next versions
1719 (let ((*ef-arith?
*))
1720 (unless (and (integerp p
) (primep p
))
1721 (gf-merror (intl:gettext
"`gf_set_data': Field characteristic must be a prime number.")) )
1725 (when a1
;; exponent or reduction poly
1728 (unless (and (fixnump a1
) (plusp a1
))
1729 (gf-merror (intl:gettext
"`gf_set_data': The exponent must be a positive fixnum.")) )
1730 (setq *gf-exp
* a1
) )
1732 (setq *gf-red
* (gf-p2x-red a1
"gf_set_data")
1733 *gf-exp
* (car *gf-red
*)
1734 *gf-irred?
* (gf-irr-p *gf-red
* *gf-char
* *gf-exp
*) )) ))
1736 (gf-set-rat-header) ;; CRE-headers
1738 (unless *gf-red
* ;; find irreducible reduction poly:
1739 (setq *gf-red
* (if (= 1 *gf-exp
*) (list 1 1) (gf-irr p
*gf-exp
*))
1742 (when (= *gf-char
* 2) (setq *f2-red
* (gf-x2n *gf-red
*)))
1744 (setq *gf-card
* (expt p
*gf-exp
*)) ;; cardinality #(F)
1746 (setq *gf-ord
* ;; group order #(F*)
1748 ((= 1 *gf-exp
*) (1- p
))
1749 ((not *gf-irred?
*) (gf-group-order *gf-char
* *gf-red
*))
1750 (t (1- (expt p
*gf-exp
*))) ))
1752 (fs (get-factor-list *gf-ord
*)) )
1753 (setq *gf-fs-ord
* (sort fs
#'< :key
#'car
)) ) ;; .. [pi, ei] ..
1755 (when *gf-irred?
* (gf-precomp))
1757 (setq *gf-prim
* ;; primitive element
1760 (if (= 2 *gf-char
*) (list 0 1)
1761 (list 0 (zn-primroot p
*gf-ord
* (mapcar #'car
*gf-fs-ord
*))) )) ;; .. pi .. (factors_only:true)
1763 (if *gf-irred?
* (gf-prim) '$unknown
) )))
1765 (setq *gf-char?
* t
*gf-red?
* t
*gf-data?
* t
) ;; global flags
1766 ($gf_get_data
) )) ;; data structure
1769 (defun gf-set-rat-header ()
1771 (setq *gf-rat-header
* (car ($rat
'$x
))) ))
1773 (defun gf-p2x-red (p fun
)
1774 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
1775 (let* ((modulus) (x (car (prep1 p
))))
1776 (unless (and (listp x
)
1777 (every #'numberp
(setq x
(cdr x
))) )
1778 (gf-merror (intl:gettext
"`~m': Not suitable as reduction polynomial: ~m") fun p
) )
1780 (unless (and (typep (car x
) 'fixnum
) (plusp (car x
)))
1781 (gf-merror (intl:gettext
"`~m': The exponent must be a positive fixnum.") fun
) )
1782 (unless (eql 1 (cadr x
))
1783 (gf-merror (intl:gettext
"`~m': A monic reduction polynomial is assumed.") fun
) )
1787 (defmfun $ef_set_data
(red)
1788 (ef-gf-field?
"ef_set_data")
1790 (let ((*ef-arith?
* t
))
1791 (setq *ef-red
* (gf-p2x-red red
"ef_set_data")
1792 *ef-exp
* (car *ef-red
*)
1793 *ef-card
* (expt *gf-card
* *ef-exp
*)
1794 *ef-irred?
* (gf-irr-p *ef-red
* *gf-card
* *ef-exp
*)
1795 *ef-ord
* (if *ef-irred?
*
1797 (gf-group-order *gf-card
* *ef-red
*) ))
1799 (fs (get-factor-list *ef-ord
*)) )
1800 (setq *ef-fs-ord
* (sort fs
#'< :key
#'car
)) )
1801 (when *ef-irred?
* (ef-precomp))
1804 *ef-prim
* (if (= 1 *ef-exp
*)
1805 (list 0 (let ((*ef-arith?
*)) (gf-x2n *gf-prim
*)))
1806 (if *ef-irred?
* (ef-prim) '$unknown
) )))
1810 (defstruct (gf-data (:print-function gf-data-short-print
))
1811 char exp red prim card
1812 ord fs-ord fsx fsx-base-p x^p-powers
)
1814 (defun gf-data-short-print (struct stream i
)
1815 (declare (ignore struct i
))
1816 (format stream
"Structure [GF-DATA]") ) ;; wxMaxima returns this
1817 ;; terminal should return this too
1819 ;; returns a struct containing all data necessary to use gf_set_again (see below)
1820 (defmfun $gf_get_data
()
1821 (gf-data?
"gf_get_data")
1823 :char
*gf-char
* ; characteristic
1824 :exp
*gf-exp
* ; exponent
1825 :red
*gf-red
* ; reduction
1826 :prim
*gf-prim
* ; primitive
1827 :card
*gf-card
* ; cardinality
1828 :ord
*gf-ord
* ; order
1829 :fs-ord
*gf-fs-ord
* ; factors of order
1830 :fsx
*gf-fsx
* ; extended factors of order
1831 :fsx-base-p
*gf-fsx-base-p
* ; extended factors in base p
1832 :x^p-powers
*gf-x^p-powers
* )) ; pre-calculated powers
1834 (defstruct (ef-data (:print-function ef-data-short-print
))
1836 ord fs-ord fsx fsx-base-q x^q-powers
)
1838 (defun ef-data-short-print (struct stream i
)
1839 (declare (ignore struct i
))
1840 (format stream
"Structure [EF-DATA]") )
1842 (defmfun $ef_get_data
()
1843 (ef-data?
"ef_get_data")
1845 :exp
*ef-exp
* ; exponent
1846 :red
*ef-red
* ; reduction
1847 :prim
*ef-prim
* ; primitive
1848 :card
*ef-card
* ; cardinality
1849 :ord
*ef-ord
* ; order
1850 :fs-ord
*ef-fs-ord
* ; factors of order
1851 :fsx
*ef-fsx
* ; extended factors of order
1852 :fsx-base-q
*ef-fsx-base-q
* ; extended factors in base q
1853 :x^q-powers
*ef-x^q-powers
* )) ; pre-calculated powers
1855 (defmfun $gf_info
(&optional
(t? t
))
1856 (gf-data?
"gf_info")
1857 (let ((no-prim (or (null *gf-prim
*) (equal *gf-prim
* '$unknown
)))
1860 "characteristic = ~a~:[, ~;~%~]~\
1861 reduction polynomial = ~a~:[, ~;~%~]~\
1862 primitive element = ~a~:[, ~;~%~]~\
1863 nr of elements = ~a~:[, ~;~%~]~\
1864 nr of units = ~a~:[, ~;~]~\
1865 ~:[~;~%nr of primitive elements = ~a~] ~%"
1867 (mfuncall '$string
(gf-x2p *gf-red
*)) t?
1871 (gf-x2p *gf-prim
*) )) t?
1873 *gf-ord
* (or t? no-prim
) (not no-prim
)
1874 (totient-by-fs-n *gf-fs-ord
*) )))
1876 (defun totient-by-fs-n (fs-n)
1878 (dolist (f fs-n phi
)
1879 (setq p
(car f
) e
(cadr f
))
1880 (setq phi
(* phi
(1- p
) (expt p
(1- e
)))) )))
1882 (defmfun $gf_infolist
() ;; enables testing gf_set_data in rtest
1883 (gf-data?
"gf_infolist")
1884 (let ((*ef-arith?
*))
1888 ,(if (or (null *gf-prim
*) (equal *gf-prim
* '$unknown
))
1890 (gf-x2p *gf-prim
*) )
1894 (defmfun $ef_info
(&optional
(t? t
))
1895 (ef-data?
"ef_info")
1896 (let ((no-prim (or (null *ef-prim
*) (equal *ef-prim
* '$unknown
)))
1899 "reduction polynomial = ~a~:[, ~;~%~]~\
1900 primitive element = ~a~:[, ~;~%~]~\
1901 nr of elements = ~a~:[, ~;~%~]~\
1902 nr of units = ~a~:[, ~;~]~\
1903 ~:[~;~%nr of primitive elements = ~a~] ~%"
1904 (mfuncall '$string
(gf-x2p *ef-red
*)) t?
1908 (gf-x2p *ef-prim
*) )) t?
1910 *ef-ord
* (or t? no-prim
) (not no-prim
)
1911 (totient-by-fs-n *ef-fs-ord
*) )))
1913 (defmfun $ef_infolist
() ;; enables testing ef_set_data in rtest
1914 (ef-data?
"ef_infolist")
1915 (let ((*ef-arith?
* t
))
1918 ,(if (or (null *ef-prim
*) (equal *ef-prim
* '$unknown
))
1920 (gf-x2p *ef-prim
*) )
1925 (defmfun $gf_unset
()
1926 (setq $gf_powers nil $gf_logs nil $gf_zech_logs nil
*gf-powers
* nil
*gf-logs?
* nil
1928 $ef_coeff_mult nil $ef_coeff_add nil $ef_coeff_inv nil $ef_coeff_exp nil
1929 *gf-rat-header
* nil
*gf-char
* 0
1930 *gf-exp
* 1 *gf-ord
* 0 *gf-card
* 0 ;; *gf-exp* = 1 when gf_set_data has no optional arg
1931 *gf-red
* nil
*f2-red
* 0 *gf-prim
* nil
1932 *gf-fs-ord
* nil
*gf-fsx
* nil
*gf-fsx-base-p
* nil
*gf-x^p-powers
* nil
1933 *gf-char?
* nil
*gf-red?
* nil
*gf-irred?
* nil
*gf-data?
* nil
)
1936 (defmfun $ef_unset
()
1937 (setq *ef-exp
* 0 *ef-ord
* 0 *ef-card
* 0
1938 *ef-red
* nil
*ef-prim
* nil
1939 *ef-fs-ord
* nil
*ef-fsx
* nil
*ef-fsx-base-q
* nil
*ef-x^q-powers
* nil
1940 *ef-red?
* nil
*ef-irred?
* nil
*ef-data?
* nil
)
1945 ;; Just set characteristic and reduction poly to allow basic arithmetics on the fly.
1946 (defmfun $gf_minimal_set
(p &optional
(red))
1947 (unless (and (integerp p
) (primep p
))
1948 (gf-merror (intl:gettext
"First argument to `gf_minimal_set' must be a prime number.")) )
1953 (let ((*ef-arith?
*))
1955 (setq *gf-red
* (gf-p2x-red red
"gf_minimal_set")
1957 *gf-exp
* (car *gf-red
*) ))
1958 (format nil
"characteristic = ~a, reduction polynomial = ~a"
1960 (if red
(mfuncall '$string
(gf-x2p *gf-red
*)) "false") )))
1963 (defmfun $ef_minimal_set
(red)
1964 (ef-gf-field?
"ef_minimal_set")
1966 (let ((*ef-arith?
* t
))
1968 (setq *ef-red
* (gf-p2x-red red
"ef_minimal_set")
1969 *ef-exp
* (car *ef-red
*)
1971 (format nil
"reduction polynomial = ~a"
1972 (if red
(mfuncall '$string
(gf-x2p *ef-red
*)) "false") )))
1975 (defmfun $gf_characteristic
()
1976 (gf-char?
"gf_characteristic")
1979 (defmfun $gf_exponent
()
1980 (gf-red?
"gf_exponent")
1983 (defmfun $gf_reduction
()
1984 (gf-red?
"gf_reduction")
1985 (when *gf-red
* (let ((*ef-arith?
*)) (gf-x2p *gf-red
*))) )
1987 (defmfun $gf_cardinality
()
1988 (gf-data?
"gf_cardinality")
1992 (defmfun $ef_exponent
()
1993 (ef-red?
"ef_exponent")
1996 (defmfun $ef_reduction
()
1997 (ef-red?
"ef_reduction")
1998 (when *ef-red
* (let ((*ef-arith?
* t
)) (gf-x2p *ef-red
*))) )
2000 (defmfun $ef_cardinality
()
2001 (ef-data?
"ef_cardinality")
2005 ;; Reuse data and results from a previous gf_set_data
2006 (defmfun $gf_set_again
(data)
2007 (unless (gf-data-p data
)
2008 (gf-merror (intl:gettext
2009 "Argument to `gf_set_again' must be a return value of `gf_set_data'." )))
2012 (setq *gf-char
* (gf-data-char data
)
2013 *gf-exp
* (gf-data-exp data
)
2014 *gf-red
* (gf-data-red data
)
2015 *gf-prim
* (gf-data-prim data
)
2016 *gf-card
* (gf-data-card data
)
2017 *gf-ord
* (gf-data-ord data
)
2018 *gf-fs-ord
* (gf-data-fs-ord data
)
2019 *gf-fsx
* (gf-data-fsx data
)
2020 *gf-fsx-base-p
* (gf-data-fsx-base-p data
)
2021 *gf-x^p-powers
* (gf-data-x^p-powers data
)
2022 *gf-irred?
* (= *gf-ord
* (1- *gf-card
*))
2027 (defmfun $ef_set_again
(data)
2028 (ef-gf-field?
"ef_set_again")
2029 (unless (ef-data-p data
)
2030 (gf-merror (intl:gettext
2031 "Argument to `ef_set_again' must be a return value of `ef_set_data'." )))
2033 (setq *ef-exp
* (ef-data-exp data
)
2034 *ef-red
* (ef-data-red data
)
2035 *ef-prim
* (ef-data-prim data
)
2036 *ef-card
* (ef-data-card data
)
2037 *ef-ord
* (ef-data-ord data
)
2038 *ef-fs-ord
* (ef-data-fs-ord data
)
2039 *ef-fsx
* (ef-data-fsx data
)
2040 *ef-fsx-base-q
* (ef-data-fsx-base-q data
)
2041 *ef-x^q-powers
* (ef-data-x^q-powers data
)
2042 *ef-irred?
* (= *ef-ord
* (1- *ef-card
*))
2046 ;; -----------------------------------------------------------------------------
2049 ;; lookup tables ---------------------------------------------------------------
2052 (defmfun $gf_make_arrays
()
2053 (format t
"`gf_make_arrays' is deprecated. ~%~\
2054 The user is asked to use `gf_make_logs' instead.~%" )
2057 (defmfun $gf_make_logs
() ;; also zech-logs and antilogs
2058 (gf-field?
"gf_make_logs")
2059 (let ((*ef-arith?
*)) (gf-make-logs)) )
2061 (defun gf-make-logs ()
2062 (unless (typep *gf-ord
* 'fixnum
)
2063 (gf-merror (intl:gettext
"`gf_make_logs': group order must be a fixnum.")) )
2064 (let ((x (list 0 1)) (ord *gf-ord
*) (primx *gf-prim
*) (red *gf-red
*))
2065 (declare (fixnum ord
))
2067 ;; power table of the field, where the i-th element is (the numerical
2068 ;; equivalent of) the field element e^i, where e is a primitive element
2070 (setq $gf_powers
(make-array (1+ ord
) :element-type
'integer
)
2071 *gf-powers
* (make-array (1+ ord
) :element-type
'list
:initial-element nil
) )
2072 (setf (svref $gf_powers
0) 1
2073 (svref *gf-powers
* 0) (list 0 1) )
2076 (declare (fixnum i
))
2077 (setq x
(gf-times x primx red
))
2078 (setf (svref $gf_powers i
) (gf-x2n x
)
2079 (svref *gf-powers
* i
) x
))
2081 ;; log table: the inverse lookup of the power table
2083 (setq $gf_logs
(make-array (1+ ord
) :initial-element nil
))
2086 (declare (fixnum i
))
2087 (setf (svref $gf_logs
(svref $gf_powers i
)) i
) )
2089 ;; zech-log table: lookup table for efficient addition
2091 (setq $gf_zech_logs
(make-array (1+ ord
) :initial-element nil
))
2092 (do ((i 0 (1+ i
)) (one (list 0 1)))
2094 (declare (fixnum i
))
2095 (setf (svref $gf_zech_logs i
)
2096 (svref $gf_logs
(gf-x2n (gf-plus (svref *gf-powers
* i
) one
))) ))
2099 `((mlist simp
) ,$gf_powers
,$gf_logs
,$gf_zech_logs
) ))
2101 (defun gf-clear-tables ()
2102 (setq $gf_powers nil
2107 ;; -----------------------------------------------------------------------------
2110 ;; converting to/from internal representation ----------------------------------
2112 ;; user level <---> internal
2114 ;; integer # 0 (0 integer') where integer' = mod(integer, *gf-char*)
2116 ;; x^4 + 3*x^2 + 4 (4 1 2 3 0 4)
2118 ;; This representation uses the term part of the internal CRE representation.
2119 ;; The coefficients are exclusively positive: 1, 2, ..., (*gf-char* -1)
2120 ;; Header information is stored in *gf-rat-header*.
2122 ;; gf_set_data(5, 4)$
2123 ;; :lisp `(,*gf-char* ,*gf-exp*)
2125 ;; p : x^4 + 3*x^2 - 1$
2127 ;; ((MRAT SIMP ($X) (X33303)) (X33303 4 1 2 3 0 -1) . 1)
2128 ;; :lisp (gf-p2x $p)
2130 ;; :lisp *gf-rat-header*
2131 ;; (MRAT SIMP ($X) (X33303))
2133 ;; Remark: I compared the timing results of the arithmetic functions using this
2134 ;; data structure to arithmetics using an array implementation and in case of
2135 ;; modulus 2 to an implementation using bit-arithmetics over integers.
2136 ;; It turns out that in all cases the timing advantages of other data structures
2137 ;; were consumed by conversions from/to the top-level.
2138 ;; So for sparse polynomials the CRE representation seems to fit best.
2142 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2143 (setq p
(car (let ((modulus)) (prep1 p
))))
2148 (t (setq p
(gf-cmod p
))
2149 (if (= p
0) nil
(list 0 p
)) )))
2151 (setq p
(gf-mod (cdr p
)))
2152 (if (typep (car p
) 'fixnum
)
2154 (gf-merror (intl:gettext
"Exponents are limited to fixnums.")) ))))
2157 ;; version of gf-p2x that doesn't apply mod reduction
2159 (defun gf-p2x-raw (p)
2160 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2161 (setq p
(car (let ((modulus)) (prep1 p
))))
2163 ((integerp p
) (if (= 0 p
) nil
(list 0 p
)))
2165 (unless (every #'numberp p
)
2166 (gf-merror (intl:gettext
"gf: polynomials must be univariate.")) )
2171 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2175 ((= 0 (the fixnum
(car x
))) (gf-cp2smod (cadr x
)))
2176 (t (gf-np2smod x
)) ))
2181 ;; depending on $gf_rat gf-x2p returns a CRE or a ratdisrepped expression
2184 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
2186 `(,*gf-rat-header
* ,x .
1)
2187 `(,*gf-rat-header
* ,(cons (caar (cdddr *gf-rat-header
*)) x
) .
1) ))
2189 (defun gf-disrep (x &optional
(var '$x
))
2190 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2192 (maybe-char-is-fixnum-let ((c 0))
2193 (do ((not-plus?
(null (cddr x
))) p
(e 0))
2194 ((null x
) (if not-plus?
(car p
) (cons '(mplus simp
) p
)))
2195 (declare (fixnum e
))
2196 (setq e
(car x
) c
(cadr x
) x
(cddr x
)
2203 (cons `((mtimes simp
) ,c
,var
) p
) ))
2205 (cons `((mexpt simp
) ,var
,e
) p
) )
2207 (cons `((mtimes simp
) ,c
((mexpt simp
) ,var
,e
)) p
) )))))))
2209 ;; -----------------------------------------------------------------------------
2212 ;; evaluation and adjustment ---------------------------------------------------
2215 ;; an arbitrary polynomial is evaluated in a given field
2217 (defmfun $gf_eval
(a)
2218 (gf-char?
"gf_eval")
2219 (let ((*ef-arith?
*)) (gf-eval a
*gf-red
* "gf_eval")) )
2221 (defmfun $ef_eval
(a)
2222 (ef-gf-field?
"ef_eval")
2223 (let ((*ef-arith?
* t
))
2224 (unless (equal a
($expand a
))
2225 (gf-merror (intl:gettext
"`ef_eval': The argument must be an expanded polynomial.")) )
2226 (gf-eval a
*ef-red
* "ef_eval") ))
2228 (defun gf-eval (a red fun
)
2229 (setq a
(let ((modulus)) (car (prep1 a
))))
2231 ((integerp a
) (gf-cmod a
))
2233 (setq a
(gf-mod (cdr a
)))
2234 (and a
(not (typep (car a
) 'fixnum
))
2235 (gf-merror (intl:gettext
"`~m': The exponent is expected to be a fixnum.") fun
) )
2236 (gf-x2p (gf-nred a red
)) )))
2239 ;; gf-mod adjusts arbitrary integer coefficients (pos, neg or unbounded)
2242 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2244 (maybe-char-is-fixnum-let ((c 0))
2245 (do ((r x
(cddr r
)) res
)
2246 ((null r
) (nreverse res
))
2247 (unless (numberp (cadr r
))
2248 (gf-merror (intl:gettext
"gf: polynomials must be univariate.")) )
2249 (setq c
(gf-cmod (cadr r
)))
2250 (unless (= c
0) (setq res
(cons c
(cons (car r
) res
)))) ))))
2252 ;; positive 2 symmetric mod:
2254 (defun gf-np2smod (x) ;; modifies x
2257 ((not $gf_balanced
) x
)
2259 (*f-np2smod x
*gf-card
* #'(lambda (c) (neg (gf-ctimes (1- *gf-char
*) c
)))) )
2261 (*f-np2smod x
*gf-char
* #'(lambda (c) (- (the integer c
) *gf-char
*))) )))
2263 (defun *f-np2smod
(x p cp2smod-fn
)
2265 (maybe-char-is-fixnum-let ((p2 (ash p -
1)))
2266 (do ((r (cdr x
) (cddr r
))) (())
2267 (when (> (the integer
(car r
)) p2
)
2268 (rplaca r
(funcall cp2smod-fn
(car r
))) )
2269 (when (null (cdr r
)) (return x
)) ))))
2271 ;; adjust a coefficient to a symmetric modulus:
2272 (defun gf-cp2smod (c)
2274 ((not $gf_balanced
) c
)
2276 (if (> c
(ash *gf-card
* -
1)) (neg (gf-ctimes c
(1- *gf-char
*))) c
) )
2278 (if (> c
(ash *gf-char
* -
1)) (- (the integer c
) *gf-char
*) c
) )))
2280 ;; -----------------------------------------------------------------------------
2283 ;; arithmetic in Galois Fields - Maxima level functions ------------------------
2288 (defmfun $gf_neg
(a)
2290 (let ((*ef-arith?
*))
2291 (gf-x2p (gf-nminus (gf-p2x a
))) ))
2293 (defmfun $gf_add
(&rest args
)
2295 (let ((*ef-arith?
*))
2296 (setq args
(mapcar #'gf-p2x args
))
2297 (gf-x2p (reduce #'gf-plus args
)) ))
2299 (defmfun $gf_sub
(&rest args
)
2301 (let ((*ef-arith?
*))
2302 (setq args
(mapcar #'gf-p2x args
))
2303 (gf-x2p (gf-plus (car args
) (gf-minus (reduce #'gf-plus
(cdr args
))))) ))
2305 (defmfun $gf_mult
(&rest args
)
2306 (gf-char?
"gf_mult")
2307 (let ((*ef-arith?
*))
2308 (setq args
(mapcar #'gf-p2x args
))
2310 (not (some #'null args
))
2311 (not (typep (apply #'+ (mapcar #'car args
)) 'fixnum
))
2312 (gf-merror (intl:gettext
"`gf_mult': Resulting exponent won't be a fixnum.")) )
2313 (gf-x2p (reduce #'(lambda (x y
) (gf-times x y
*gf-red
*)) args
)) ))
2315 (defmfun $gf_reduce
(a b
)
2316 (gf-char?
"gf_reduce")
2317 (let ((*ef-arith?
*))
2318 (gf-x2p (gf-nrem (gf-p2x a
) (gf-p2x b
))) ))
2320 (defmfun $gf_inv
(a)
2322 (let ((*ef-arith?
*))
2323 (setq a
(gf-inv (gf-p2x a
) *gf-red
*))
2324 (when a
(gf-x2p a
)) )) ;; a is nil in case the inverse does not exist
2326 (defmfun $gf_div
(&rest args
)
2329 (gf-merror (intl:gettext
"`gf_div' needs at least two arguments." )) )
2330 (let* ((*ef-arith?
*)
2331 (a2 (mapcar #'gf-p2x args
))
2332 (a2 (cons (car a2
) (mapcar #'(lambda (x) (gf-inv x
*gf-red
*)) (cdr a2
)))) )
2334 ((some #'null
(cdr a2
)) ;; but check if exact division is possible ..
2335 (let ((q (gf-p2x (car args
))) r
)
2336 (setq args
(cdr args
))
2337 (do ((d (car args
) (car args
)))
2338 ((null d
) (gf-x2p q
))
2339 (multiple-value-setq (q r
) (gf-divide q
(gf-p2x d
)))
2340 (when r
(return)) ;; .. in case it is not return false
2341 (setq args
(cdr args
)) )))
2342 (t ;; a / b = a * b^-1 :
2343 (gf-x2p (reduce #'(lambda (x y
) (gf-times x y
*gf-red
*)) a2
)) ))))
2345 (defmfun $gf_exp
(a n
)
2347 (let ((*ef-arith?
*))
2350 (gf-merror (intl:gettext
"`gf_exp' needs two arguments.")) )
2352 (gf-merror (intl:gettext
"Second argument to `gf_exp' must be an integer.")) )
2353 ((< (the integer n
) 0)
2355 (gf-merror (intl:gettext
"`gf_exp': Unknown reduction polynomial.")) )
2356 (setq a
(gf-inv (gf-p2x a
) *gf-red
*))
2357 (when a
($gf_exp
(gf-x2p a
) (neg n
))) ) ;; a is nil in case the inverse does not exist
2359 (gf-x2p (gf-pow-by-table (gf-p2x a
) n
)) )
2360 ((and *gf-irred?
* *gf-x^p-powers
*)
2361 (gf-x2p (gf-pow$
(gf-p2x a
) n
*gf-red
*)) )
2366 (not (typep (* n
(car a
)) 'fixnum
))
2367 (gf-merror (intl:gettext
"`gf_exp': Resulting exponent won't be a fixnum.")) )
2368 (gf-x2p (gf-pow a n
*gf-red
*)) ))))
2372 (defmfun $ef_neg
(a)
2373 (ef-gf-field?
"ef_neg")
2374 (let ((*ef-arith?
* t
))
2375 (gf-x2p (gf-nminus (gf-p2x a
))) ))
2377 (defmfun $ef_add
(&rest args
)
2378 (ef-gf-field?
"ef_add")
2379 (let ((*ef-arith?
* t
))
2380 (setq args
(mapcar #'gf-p2x args
))
2381 (gf-x2p (reduce #'gf-plus args
)) ))
2383 (defmfun $ef_sub
(&rest args
)
2384 (ef-gf-field?
"ef_sub")
2385 (let ((*ef-arith?
* t
))
2386 (setq args
(mapcar #'gf-p2x args
))
2387 (gf-x2p (gf-plus (car args
) (gf-minus (reduce #'gf-plus
(cdr args
))))) ))
2389 (defmfun $ef_mult
(&rest args
)
2390 (ef-gf-field?
"ef_mult")
2391 (let ((*ef-arith?
* t
)
2393 (setq args
(mapcar #'gf-p2x args
))
2395 (not (some #'null args
))
2396 (not (typep (apply #'+ (mapcar #'car args
)) 'fixnum
))
2397 (gf-merror (intl:gettext
"`ef_mult': Resulting exponent won't be a fixnum.")) )
2398 (gf-x2p (reduce #'(lambda (x y
) (gf-times x y red
)) args
)) ))
2400 (defmfun $ef_reduce
(a b
)
2401 (ef-gf-field?
"ef_reduce")
2402 (let ((*ef-arith?
* t
))
2403 (gf-x2p (gf-nrem (gf-p2x a
) (gf-p2x b
))) ))
2405 (defmfun $ef_inv
(a)
2407 (let ((*ef-arith?
* t
))
2408 (setq a
(gf-inv (gf-p2x a
) *ef-red
*))
2409 (when a
(gf-x2p a
)) ))
2411 (defmfun $ef_div
(&rest args
)
2414 (gf-merror (intl:gettext
"`ef_div' needs at least two arguments." )) )
2415 (let ((*ef-arith?
* t
)
2417 (setq args
(mapcar #'gf-p2x args
))
2419 (cons (car args
) (mapcar #'(lambda (x) (gf-inv x red
)) (cdr args
))) )
2421 ((null (car args
)) 0)
2422 ((some #'null
(cdr args
)) nil
)
2423 (t (gf-x2p (reduce #'(lambda (x y
) (gf-times x y red
)) args
))) )))
2425 (defmfun $ef_exp
(a n
)
2426 (ef-gf-field?
"ef_exp")
2427 (let ((*ef-arith?
* t
))
2429 ((< (the integer n
) 0)
2431 (gf-merror (intl:gettext
"`ef_exp': Unknown reduction polynomial.")) )
2432 (setq a
(gf-inv (gf-p2x a
) *ef-red
*))
2433 (when a
($ef_exp
(gf-x2p a
) (neg n
))) )
2434 ((and *ef-irred?
* *ef-x^q-powers
*)
2435 (gf-x2p (gf-pow$
(gf-p2x a
) n
*ef-red
*)) )
2440 (not (typep (* n
(car a
)) 'fixnum
))
2441 (gf-merror (intl:gettext
"`ef_exp': Resulting exponent won't be a fixnum.")) )
2442 (gf-x2p (gf-pow a n
*ef-red
*)) ))))
2444 ;; -----------------------------------------------------------------------------
2447 ;; arithmetic in Galois Fields - Lisp level functions --------------------------
2450 ;; Both gf (base field) and ef (extension field) Maxima level functions use
2451 ;; this Lisp level functions. The switch *ef-arith?* controls how the coefficients
2452 ;; were treated. The coefficient functions gf-ctimes and friends behave
2453 ;; differently depending on *ef-arith?*. See above definitions.
2455 ;; Remark: A prefixed character 'n' indicates a destructive function.
2459 (defun gf-xctimes (x c
)
2460 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2461 (maybe-char-is-fixnum-let ((c c
))
2462 (if (or (= 0 c
) (null x
)) nil
2463 (do* ((res (list (car x
) (gf-ctimes c
(cadr x
))))
2464 (r (cdr res
) (cddr r
))
2465 (rx (cddr x
) (cddr rx
)) )
2467 (rplacd r
(list (car rx
) (gf-ctimes c
(cadr rx
)))) ))))
2469 (defun gf-nxctimes (x c
) ;; modifies x
2470 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2471 (maybe-char-is-fixnum-let ((c c
))
2472 (if (or (= 0 c
) (null x
)) nil
2473 (do ((r (cdr x
) (cddr r
)))
2475 (rplaca r
(gf-ctimes c
(car r
))) ))))
2479 (defun gf-xectimes (x e c
)
2480 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2481 (declare (fixnum e
))
2482 (maybe-char-is-fixnum-let ((c c
))
2483 (if (or (= 0 c
) (null x
)) nil
2484 (do* ((res (list (+ e
(the fixnum
(car x
))) (gf-ctimes c
(cadr x
))))
2485 (r (cdr res
) (cddr r
))
2486 (rx (cddr x
) (cddr rx
)) )
2488 (rplacd r
(list (+ e
(the fixnum
(car rx
))) (gf-ctimes c
(cadr rx
)))) ))))
2492 (defun gf-nxetimes (x e
) ;; modifies x
2494 (do ((r x
(cddr r
)))
2496 (rplaca r
(+ e
(car r
))) )))
2501 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2502 (if (or (null x
) (= 2 *gf-char
*)) x
2503 (do* ((res (list (car x
) (gf-cminus-b (cadr x
))))
2504 (r (cdr res
) (cddr r
))
2505 (rx (cddr x
) (cddr rx
)) )
2507 (rplacd r
(list (car rx
) (gf-cminus-b (cadr rx
)))) )))
2509 (defun gf-nminus (x) ;; modifies x
2510 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2511 (if (or (null x
) (= 2 *gf-char
*)) x
2512 (do ((r (cdr x
) (cddr r
))) (())
2513 (rplaca r
(gf-cminus-b (car r
)))
2514 (when (null (cdr r
)) (return x
)) )))
2518 (defun gf-plus (x y
)
2522 (t (gf-nplus (copy-list x
) y
)) ))
2526 (defun gf-nplus (x y
) ;; modifies x
2527 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2532 (maybe-char-is-fixnum-let ((cy 0)(c 0))
2533 (prog ((ex 0)(ey 0) r
) (declare (fixnum ex ey
))
2535 (setq ex
(car x
) ey
(car y
) cy
(cadr y
))
2538 (setq x
(cons ey
(cons cy x
)) y
(cddr y
)) )
2540 (setq c
(gf-cplus-b (cadr x
) cy
) y
(cddr y
))
2543 (when (null (setq x
(cddr x
))) (return y
))
2544 (when (null y
) (return x
))
2546 (t (rplaca (cdr x
) c
)) ))
2547 (t (setq r
(cdr x
)) (go b
)) )
2550 (when (null y
) (return x
))
2551 (setq ey
(car y
) cy
(cadr y
))
2553 (while (and (cdr r
) (> (the fixnum
(cadr r
)) ey
))
2556 ((null (cdr r
)) (rplacd r y
) (return x
))
2557 ((> ey
(the fixnum
(cadr r
)))
2558 (rplacd r
(cons ey
(cons cy
(cdr r
))))
2559 (setq r
(cddr r
) y
(cddr y
)) )
2561 (setq c
(gf-cplus-b (caddr r
) cy
) y
(cddr y
))
2563 (rplacd r
(cdddr r
))
2564 (rplaca (setq r
(cddr r
)) c
) )) )
2569 (defun gf-xyecplus (x y e c
)
2572 ((null x
) (gf-xectimes y e c
))
2573 (t (gf-nxyecplus (copy-list x
) y e c
) )))
2575 ;; merge c*v^e*y into x
2577 (defun gf-nxyecplus (x y e c
) ;; modifies x
2578 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2581 ((null x
) (gf-xectimes y e c
))
2583 (maybe-char-is-fixnum-let ((cy 0) (cc 0))
2584 (prog ((e e
) (ex 0) (ey 0) r
) (declare (fixnum e ex ey
))
2586 (setq ey
(+ (the fixnum
(car y
)) e
)
2587 cy
(gf-ctimes c
(cadr y
))
2591 (setq x
(cons ey
(cons cy x
)) y
(cddr y
)) )
2593 (setq cc
(gf-cplus-b (cadr x
) cy
) y
(cddr y
))
2596 (when (null (setq x
(cddr x
))) (return (gf-xectimes y e c
)))
2597 (when (null y
) (return x
))
2599 (t (rplaca (cdr x
) cc
)) ))
2600 (t (setq r
(cdr x
)) (go b
)) )
2603 (when (null y
) (return x
))
2604 (setq ey
(+ (the fixnum
(car y
)) e
)
2605 cy
(gf-ctimes c
(cadr y
)) )
2607 (when (null (cdr r
)) (go d
))
2611 (rplacd r
(cons ey
(cons cy
(cdr r
))))
2612 (setq r
(cddr r
) y
(cddr y
))
2615 (setq cc
(gf-cplus-b (caddr r
) cy
))
2617 (rplacd r
(cdddr r
))
2618 (rplaca (setq r
(cddr r
)) cc
) )
2621 (t (setq r
(cddr r
)) (go b
)) )
2624 (setq x
(nconc x
(list (+ (the fixnum
(car y
)) e
) (gf-ctimes c
(cadr y
))))
2630 ;; For sparse polynomials (in Galois Fields) with not too high degrees
2631 ;; simple school multiplication is faster than Karatsuba.
2633 ;; x * y = (x1 + x2 + ... + xk) * (y1 + y2 + ... + yn)
2634 ;; = x1 * (y1 + y2 + ... + yn) + x2 * (y1 + y2 + ... + yn) + ...
2636 ;; where e.g. xi = ci*v^ei
2638 (defun gf-times (x y red
)
2639 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2640 (if (or (null x
) (null y
)) nil
2641 (maybe-char-is-fixnum-let ((c 0) (cx 0))
2642 (do* ((res (gf-xectimes y
(car x
) (cadr x
))) ;; x1 * (y1 + y2 + ... + yn). summands in res are sorted. res is a new list.
2643 (r1 (cdr res
)) ;; r1 marks the place of xi*y1 in res. x[i+1]*y1 will be smaller.
2644 ry
;; ry iterates over y
2645 (x (cddr x
) (cddr x
)) ;; each loop: res += xi * (y1 + y2 + ... + yn)
2647 ((or (null x
)(null y
)) (gf-nred res red
))
2648 (declare (fixnum e ex
))
2649 (setq ry y
;; start with y1 again
2650 ex
(car x
) cx
(cadr x
) ;; xi = ci*v^ei
2651 e
(+ ex
(the fixnum
(car ry
))) ;; c*v^e = xi*y1
2652 c
(gf-ctimes (cadr ry
) cx
) ) ;; zero divisor free mult in Fp^n
2654 (while (and (cdr r1
) (< e
(the fixnum
(cadr r1
))))
2655 (setq r1
(cddr r1
)) ) ;; mark the position of xi*y1
2657 (do ((r r1
)) (()) ;; merge xi*y1 into res and then xi*y2, etc...
2659 ((or (null (cdr r
)) (> e
(the fixnum
(cadr r
))))
2660 (rplacd r
(cons e
(cons c
(cdr r
))))
2662 ((= 0 (setq c
(gf-cplus-b (caddr r
) c
)))
2663 (rplacd r
(cdddr r
)) )
2664 (t (rplaca (setq r
(cddr r
)) c
)) )
2666 (when (null (setq ry
(cddr ry
))) (return))
2667 (setq e
(+ ex
(the fixnum
(car ry
)))
2668 c
(gf-ctimes (cadr ry
) cx
) )
2670 (while (and (cdr r
) (< e
(the fixnum
(cadr r
))))
2671 (setq r
(cddr r
)) ) )) )))
2675 ;; x * x = (x_1 + x_2 + ... + x_k) * (x_1 + x_2 + ... + x_k)
2677 ;; = 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 + ...
2679 ;; = 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 + ...
2681 ;; The reverse needs some additional consing but is slightly faster.
2683 (defun gf-sq (x red
)
2684 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2687 ((and (not *ef-arith?
*) (eql *gf-char
* 2)) ;; the mod 2 case degrades to x_1^2 + x_2^2 + ... + x_k^2
2689 ((null x
) (gf-nred (nreverse res
) red
))
2690 (setq res
(cons 1 (cons (ash (car x
) 1) res
))
2693 (maybe-char-is-fixnum-let ((ci 0)(*2ci
0)(c 0))
2694 (setq x
(reverse x
)) ;; start with x_k
2695 (prog (res ;; result
2696 r
;; insertion marker in res
2697 acc
;; acc accumulates previous x_i
2698 r1
;; r1 iterates in each loop over acc
2699 (e 0) (ei 0) ) (declare (fixnum e ei
))
2701 (setq ci
(car x
) ei
(cadr x
) ;; x_i = ci*v^ei
2702 *2ci
(gf-cplus-b ci ci
) ;; 2*ci (2*ci # 0 when *gf-char* # 2)
2703 res
(cons (+ ei ei
) (cons (gf-ctimes ci ci
) res
)) ;; res += x_i^2 (ci^2 # 0, no zero divisors)
2704 r
(cdr res
) ;; place insertion marker behind x_i^2
2707 (when (or (null r1
) (= 0 *2ci
)) ;; in ef *2ci might be 0 !
2708 (when (null (setq x
(cddr x
))) (return (gf-nred res red
)))
2709 (setq acc
(cons ei
(cons ci acc
))) ;; cons previous x_i to acc ..
2710 (go a1
) ) ;; .. and start next loop
2712 (setq e
(+ ei
(the fixnum
(car r1
)))
2713 c
(gf-ctimes *2ci
(cadr r1
))
2716 (while (< e
(the fixnum
(cadr r
)))
2719 ((> e
(the fixnum
(cadr r
)))
2720 (rplacd r
(cons e
(cons c
(cdr r
))))
2723 (setq c
(gf-cplus-b c
(caddr r
)))
2725 (rplacd r
(cdddr r
))
2726 (rplaca (setq r
(cddr r
)) c
) ) ))
2731 (defun gf-pow (x n red
) ;; assume 0 <= n
2732 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2733 (declare (integer n
))
2735 ((= 0 n
) (list 0 1))
2739 (setq res
(if res
(gf-times x res red
) x
))
2741 (return-from gf-pow res
) ))
2743 x
(gf-sq x red
)) ))))
2745 ;; in a field use precomputed *gf-x^p-powers* resp. *ef-x^q-powers*
2747 (defun gf-pow$
(x n red
)
2750 (*f-pow$ x n red
*gf-card
* *ef-card
* *ef-x^q-powers
*)
2753 (*f-pow$ x n red
*gf-char
* *gf-card
* *gf-x^p-powers
*)
2754 (gf-pow x n red
) )))
2756 (defun *f-pow$
(x n red p card x^p-powers
)
2757 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2758 (declare (integer n p card
))
2760 ((= 0 n
) (list 0 1))
2762 ((>= n card
) (gf-pow x n red
))
2764 (let ((prod (list 0 1))
2766 (do (quo r
) ((= 0 n
))
2767 (multiple-value-setq (quo r
) (truncate n p
))
2770 (dolist (ni (nreverse n-base-p
))
2771 (setq y
(gf-compose (svref x^p-powers j
) x red
)
2773 prod
(gf-times prod y red
)
2778 ;; x - quotient(x, y) * y
2782 (gf-merror (intl:gettext
"~m arithmetic: Quotient by zero") (if *ef-arith?
* "ef" "gf")) )
2784 (gf-nrem (copy-list x
) y
) ))
2786 (defun gf-nrem (x y
) ;; modifies x
2787 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2789 (gf-merror (intl:gettext
"~m arithmetic: Quotient by zero") (if *ef-arith?
* "ef" "gf")) )
2791 (maybe-char-is-fixnum-let ((c 0) (lcx 0) (lcy-inv (gf-cinv (cadr y
))))
2792 (let ((e 0) (ley (car y
)))
2793 (declare (fixnum e ley
))
2794 (setq lcy-inv
(gf-cminus-b lcy-inv
))
2797 (setq e
(- (the fixnum
(car x
)) ley
))
2798 (when (< e
0) (return x
))
2800 c
(gf-ctimes lcx lcy-inv
)
2801 x
(gf-nxyecplus (cddr x
) y e c
)) )))))
2805 ;; assume lc(red) = 1, reduction poly is monic
2807 (defun gf-nred (x red
) ;; modifies x
2808 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2809 (if (or (null x
) (null red
)) x
2810 (let ((e 0) (le-red (car red
)))
2811 (declare (fixnum e le-red
))
2812 (setq red
(cddr red
))
2814 (setq e
(- (the fixnum
(car x
)) le-red
))
2815 (when (< e
0) (return x
))
2816 (setq x
(gf-nxyecplus (cddr x
) red e
(gf-cminus-b (cadr x
)))) ))))
2821 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
2827 (if (eql 0 (car x
)) (list 0 1)
2828 (gf-xctimes x
(gf-cinv (cadr x
))) ))
2829 (setq r
(gf-rem x y
))
2830 (psetf x y y r
) )))))
2832 ;; (monic) extended gcd
2834 (defun gf-gcdex (x y red
)
2835 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
2836 (let ((x1 (list 0 1)) x2 y1
(y2 (list 0 1)) q r
)
2838 (let ((inv (gf-cinv (cadr x
))))
2839 (mapcar #'(lambda (a) (gf-xctimes a inv
)) (list x1 x2 x
)) ))
2840 (multiple-value-setq (q r
) (gf-divide x y
))
2843 y1
(gf-nplus (gf-nminus (gf-times q y1 red
)) x1
)
2846 y2
(gf-nplus (gf-nminus (gf-times q y2 red
)) x2
)
2851 ;; in case the inverse does not exist it returns nil
2852 ;; (might happen when reduction poly isn't irreducible)
2854 (defun gf-inv (y red
)
2855 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2857 (gf-merror (intl:gettext
"~m arithmetic: Quotient by zero") (if *ef-arith?
* "ef" "gf")) )
2858 (let ((y1 (list 0 1)) (x red
) x1 q r
)
2859 (setq y
(copy-list y
))
2861 (when (= 0 (car x
)) ;; gcd = 1 (const)
2862 (gf-nxctimes x1
(gf-cinv (cadr x
))) ))
2863 (multiple-value-setq (q r
) (gf-divide x y
))
2867 y1
(gf-nplus (gf-nminus (gf-times q y1 red
)) x1
) )) ))
2869 ;; quotient and remainder
2871 (defun gf-divide (x y
)
2872 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2875 (gf-merror (intl:gettext
"~m arithmetic: Quotient by zero") (if *ef-arith?
* "ef" "gf")) )
2876 ((null x
) (values nil nil
))
2878 (maybe-char-is-fixnum-let ((c 0) (lcx 0) (lcyi (gf-cinv (cadr y
))))
2879 (let ((e 0) (ley (car y
)))
2880 (declare (fixnum e ley
))
2881 (setq x
(copy-list x
))
2882 (do (q (y (cddr y
)))
2883 ((null x
) (values (nreverse q
) x
))
2884 (setq e
(- (the fixnum
(car x
)) ley
))
2886 (return (values (nreverse q
) x
)) )
2889 c
(gf-ctimes lcx lcyi
) )
2890 (unless (null y
) (setq x
(gf-nxyecplus x y e
(gf-cminus-b c
))))
2891 (setq q
(cons c
(cons e q
))) ))))))
2893 ;; -----------------------------------------------------------------------------
2896 ;; polynomial/number/list - conversions ----------------------------------------
2901 (defmfun $ef_p2n
(p)
2903 (let ((*ef-arith?
* t
)) (gf-x2n (gf-p2x p
))) )
2905 (defmfun $gf_p2n
(p &optional gf-char
)
2906 (let ((*ef-arith?
*))
2909 (let ((*gf-char
* gf-char
)) (gf-x2n (gf-p2x p
))) )
2911 (gf-x2n (gf-p2x p
)) )
2913 (gf-merror (intl:gettext
"`gf_p2n': missing modulus.")) ))))
2916 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2918 (maybe-char-is-fixnum-let ((m *gf-char
*))
2919 (when *ef-arith?
* (setq m
*gf-card
*))
2923 (return (* n
(expt m
(the fixnum
(car x
)))))
2924 (setq n
(* n
(expt m
(- (the fixnum
(car x
)) (the fixnum
(caddr x
)))))) )
2925 (setq x
(cddr x
)) ))))
2929 (defun gf-n2p-errchk (fun n
)
2930 (unless (integerp n
)
2931 (gf-merror (intl:gettext
"`~m': Not an integer: ~m") fun n
) ))
2933 (defmfun $gf_n2p
(n &optional gf-char
)
2934 (gf-n2p-errchk "gf_n2p" n
)
2935 (let ((*ef-arith?
*))
2939 (let ((*gf-char
* gf-char
)) (gf-x2p (gf-n2x n
))) )
2941 (gf-x2p (gf-n2x n
)) )
2943 (gf-merror (intl:gettext
"`gf_n2p': missing modulus.")) ))))
2945 (defmfun $ef_n2p
(n)
2947 (gf-n2p-errchk "ef_n2p" n
)
2948 (let ((*ef-arith?
* t
)) (gf-x2p (gf-n2x n
))) )
2951 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
2952 (declare (integer n
))
2953 (maybe-char-is-fixnum-let ((r 0) (m *gf-char
*))
2954 (let ((e 0)) (declare (fixnum e
))
2955 (when *ef-arith?
* (setq m
*gf-card
*))
2958 (multiple-value-setq (n r
) (truncate n m
))
2960 (setq x
(cons e
(cons r x
))) )
2965 (defmfun $ef_p2l
(p &optional
(len 0))
2966 (declare (fixnum len
))
2967 (let ((*ef-arith?
* t
))
2968 (cons '(mlist simp
) (gf-x2l (gf-p2x-raw p
) len
)) )) ;; more flexibility ...
2970 (defmfun $gf_p2l
(p &optional
(len 0)) ;; len = 0 : no padding
2971 (declare (fixnum len
))
2972 (let ((*ef-arith?
*))
2973 (cons '(mlist simp
) (gf-x2l (gf-p2x-raw p
) len
)) )) ;; ... by omitting mod reduction
2975 (defun gf-x2l (x len
)
2976 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
2977 (declare (fixnum len
))
2978 (do* ((e (if x
(the fixnum
(car x
)) 0))
2979 (k (max e
(1- len
)) (1- k
))
2981 ((< k
0) (nreverse l
))
2982 (declare (fixnum e k
))
2984 ((or (null x
) (> k e
))
2989 (unless (null x
) (setq e
(the fixnum
(car x
)))) ))))
2993 (defmfun $ef_l2p
(l)
2994 (gf-l2p-errchk l
"ef_l2p")
2995 (let ((*ef-arith?
* t
)) (gf-x2p (gf-l2x (cdr l
)))) )
2997 (defmfun $gf_l2p
(l)
2998 (gf-l2p-errchk l
"gf_l2p")
2999 (let ((*ef-arith?
*)) (gf-x2p (gf-l2x (cdr l
)))) )
3001 (defun gf-l2p-errchk (l fun
)
3003 (gf-merror (intl:gettext
"`~m': Argument must be a list of integers.") fun
) ))
3006 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3007 (setq l
(reverse l
))
3008 (maybe-char-is-fixnum-let ((c 0))
3009 (let ((e 0)) (declare (fixnum e
))
3012 (unless (= 0 (setq c
(car l
)))
3013 (setq x
(cons e
(cons c x
))) )
3019 (defmfun $gf_l2n
(l)
3021 (gf-l2p-errchk l
"gf_l2n")
3022 (let ((*ef-arith?
*)) (gf-l2n (cdr l
))) )
3024 (defmfun $ef_l2n
(l)
3026 (gf-l2p-errchk l
"ef_l2n")
3027 (let ((*ef-arith?
* t
)) (gf-l2n (cdr l
))) )
3030 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3031 (maybe-char-is-fixnum-let ((m *gf-char
*) (c1 (car l
)) (c 0))
3032 (when *ef-arith?
* (setq m
*gf-card
*))
3033 (setq l
(reverse (cdr l
)))
3035 ((null l
) (+ (* c1 b
) n
))
3036 (declare (integer n b
))
3037 (unless (= 0 (setq c
(car l
))) (incf n
(* c b
)))
3038 (setq b
(* b m
) l
(cdr l
)) )))
3042 (defmfun $gf_n2l
(n &optional
(len 0)) ;; in case of len = 0 the list isn't padded or truncated
3043 (declare (integer n
) (fixnum len
))
3045 (gf-n2p-errchk "gf_n2l" n
)
3047 (let ((*ef-arith?
*))
3048 (if (= 0 len
) (gf-n2l n
) (gf-n2l-twoargs n len
)) )))
3050 (defmfun $ef_n2l
(n &optional
(len 0)) ;; in case of len = 0 the list isn't padded or truncated
3051 (declare (integer n
) (fixnum len
))
3053 (gf-n2p-errchk "ef_n2l" n
)
3055 (let ((*ef-arith?
* t
))
3056 (if (= 0 len
) (gf-n2l n
) (gf-n2l-twoargs n len
)) )))
3058 (defun gf-n2l (n) ;; this version is frequently called by gf-precomp, keep it simple
3059 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3060 (declare (integer n
))
3061 (maybe-char-is-fixnum-let ((m *gf-char
*) (r 0))
3062 (when *ef-arith?
* (setq m
*gf-card
*))
3064 (multiple-value-setq (n r
) (truncate n m
))
3065 (setq l
(cons r l
)) )))
3067 (defun gf-n2l-twoargs (n len
)
3068 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3069 (declare (integer n
) (fixnum len
))
3070 (maybe-char-is-fixnum-let ((m *gf-char
*) (r 0))
3071 (when *ef-arith?
* (setq m
*gf-card
*))
3072 (do (l) ((= 0 len
) l
)
3073 (multiple-value-setq (n r
) (truncate n m
))
3077 ;; -----------------------------------------------------------------------------
3080 ;; irreducibility (Ben-Or algorithm) -------------------------------------------
3083 (defmfun $gf_irreducible_p
(a &optional p
)
3085 (p (unless (and (integerp p
) (primep p
))
3086 (gf-merror (intl:gettext
3087 "`gf_irreducible_p': Second argument must be a prime number." )) ))
3088 (t (gf-char?
"gf_irreducible_p")
3089 (setq p
*gf-char
*) ))
3090 (let* ((*ef-arith?
*)
3092 (x (gf-p2x a
)) n
) ;; gf-p2x depends on *gf-char*
3095 ((= 0 (setq n
(car x
))) nil
)
3097 (t (gf-irr-p x p
(car x
))) )))
3099 (defmfun $ef_irreducible_p
(a)
3100 (ef-gf-field?
"ef_irreducible_p")
3101 (let ((*ef-arith?
* t
))
3103 (gf-irr-p a
*gf-card
* (car a
)) ))
3105 ;; is y irreducible of degree n over Fq[x] ?
3108 (defun gf-irr-p (y q n
) ;; gf-irr-p is independent from any settings
3109 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3110 (declare (integer q
) (fixnum n
))
3111 (let* ((*gf-char
* (car (cfactorw q
)))
3113 (mx (gf-minus x
)) ;; gf-minus needs *gf-char*
3116 (setq y
(gf-xctimes y
(gf-cinv lc
))) ) ;; monicize y
3117 (do ((i 1 (1+ i
)) (xq x
) (n2 (ash n -
1)))
3119 (declare (fixnum i n2
))
3120 (setq xq
(gf-pow xq q y
))
3121 (unless (= 0 (car (gf-gcd y
(gf-plus xq mx
))))
3124 ;; find an irreducible element
3126 ;; gf_irreducible is independent from any settings
3128 (defmfun $gf_irreducible
(p n
) ;; p,n : desired characteristic and degree
3129 (unless (and (integerp p
) (primep p
) (integerp n
))
3130 (gf-merror (intl:gettext
"`gf_irreducible' needs a prime number and an integer.")) )
3132 (let* ((*gf-char
* p
)
3134 (irr (gf-irr p n
)) )
3135 (when irr
(gf-x2p irr
)) ))
3137 (defmfun $ef_irreducible
(n) ;; n : desired degree
3138 (ef-gf-field?
"ef_irreducible")
3139 (unless (integerp n
)
3140 (gf-merror (intl:gettext
"`ef_irreducible' needs an integer.")) )
3141 (let* ((*ef-arith?
* t
)
3143 (when irr
(gf-x2p irr
)) ))
3150 (*f-irr
*gf-card
* n
) )
3153 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3155 (return-from *f-irr
(list 1 1)) )
3156 (let* ((inc (min $gf_coeff_limit q
))
3157 (i-lim (expt inc n
))
3161 (gf-merror (intl:gettext
"No irreducible polynomial found.~%~\
3162 `gf_coeff_limit' might be too small.~%" )))
3163 (setq x
(let ((*gf-char
* inc
)) (gf-n2x i
)))
3164 (when (= 0 (car (last x
2)))
3165 (setq x
(cons n
(cons 1 x
)))
3166 (when (gf-irr-p x q n
) (return-from *f-irr x
)) ))))
3168 ;; -----------------------------------------------------------------------------
3171 ;; Primitive elements ----------------------------------------------------------
3174 ;; Tests if an element is primitive in the field
3176 (defmfun $gf_primitive_p
(a)
3177 (gf-data?
"gf_primitive_p") ;; --> precomputations are performed
3178 (let* ((*ef-arith?
*)
3182 ((or (= 0 n
) (>= n
*gf-card
*)) nil
)
3184 (zn-primroot-p n
*gf-char
* *gf-ord
* (mapcar #'car
*gf-fs-ord
*)) )
3188 (defmfun $ef_primitive_p
(a)
3189 (ef-data?
"ef_primitive_p") ;; --> precomputations are performed
3190 (let ((*ef-arith?
* t
))
3194 ((>= (car a
) *ef-exp
*) nil
)
3197 (let ((*ef-arith?
*)) (gf-prim-p (gf-n2x (cadr a
))))
3199 (t (ef-prim-p a
)) )))
3202 ;; Testing primitivity in (Fq^n)*:
3204 ;; We check f(x)^ei # 1 (ei = ord/pi) for all prime factors pi of ord.
3206 ;; With ei = sum(aij*q^j, j,0,m) in base q and using f(x)^q = f(x^q) we get
3208 ;; f(x)^ei = f(x)^sum(aij*q^j, j,0,m) = prod(f(x^q^j)^aij, j,0,m).
3211 ;; Special case: red is irreducible, f(x) = x+c and pi|ord and pi|q-1.
3213 ;; Then ei = (q^n-1)/(q-1) * (q-1)/pi = sum(q^j, j,0,n-1) * (q-1)/pi.
3215 ;; With ai = (q-1)/pi and using red(z) = prod(z - x^q^j, j,0,n-1) we get
3217 ;; f(x)^ei = f(x)^sum(ai*q^j, j,0,n-1) = (prod(f(x)^q^j, j,0,n-1))^ai
3219 ;; = (prod(x^q^j + c, j,0,n-1))^ai = ((-1)^n * prod(-c - x^q^j, j,0,n-1))^ai
3221 ;; = ((-1)^n * red(-c))^ai
3224 (defun gf-prim-p (x)
3227 (*f-prim-p-2 x
*gf-char
* *gf-red
* *gf-fsx
* *gf-fsx-base-p
* *gf-x^p-powers
*) )
3228 ((gf-unit-p x
*gf-red
*)
3229 (*f-prim-p-1 x
*gf-red
* *gf-ord
* *gf-fs-ord
*) )
3232 (defun ef-prim-p (x)
3235 (*f-prim-p-2 x
*gf-card
* *ef-red
* *ef-fsx
* *ef-fsx-base-q
* *ef-x^q-powers
*) )
3236 ((gf-unit-p x
*ef-red
*)
3237 (*f-prim-p-1 x
*ef-red
* *ef-ord
* *ef-fs-ord
*) )
3242 (defun *f-prim-p-1
(x red ord fs-ord
)
3243 (dolist (pe fs-ord t
)
3244 (when (equal '(0 1) (gf-pow x
(truncate ord
(car pe
)) red
)) (return)) ))
3246 ;; *f-prim-p-2 uses precomputations and exponentiation by composition
3248 (defun *f-prim-p-2
(x q red fs fs-base-q x^q-powers
)
3249 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3250 (unless (or (= 2 *gf-char
*) (= -
1 (gf-jacobi x red q
))) ;; red is assumed to be irreducible
3251 (return-from *f-prim-p-2
) )
3252 (let ((exponent (car red
))
3253 (x+c?
(and (= (car x
) 1) (= (cadr x
) 1)))
3255 (do ((i 0 (1+ i
)) (j 0 0) (lf (array-dimension fs
0)))
3257 (declare (fixnum i j lf
))
3259 ((and x
+c?
(cadr (svref fs i
))) ;; linear and pi|ord and pi|p-1
3260 (setq -c
(if (= 2 (length x
)) 0 (gf-cminus-b (car (last x
))))
3261 z
(list 0 (gf-at red -c
)) )
3262 (when (oddp exponent
) (setq z
(gf-minus z
))) ;; (-1)^n * red(-c)
3263 (setq z
(gf-pow z
(caddr (svref fs i
)) red
)) ;; ((-1)^n * red(-c))^ai
3264 (when (or (null z
) (equal z
'(0 1)))
3267 (setq prod
(list 0 1))
3268 (dolist (aij (svref fs-base-q i
))
3269 (setq y
(gf-compose (svref x^q-powers j
) x red
) ;; f(x^q^j)
3270 y
(gf-pow y aij red
) ;; f(x^q^j)^aij
3271 prod
(gf-times prod y red
)
3273 (when (or (null prod
) (equal prod
'(0 1))) ;; prod(f(x^q^j)^aij, j,0,m)
3274 (return nil
) )) ))))
3277 ;; generalized Jacobi-symbol (Bach-Shallit, Theorem 6.7.1)
3279 (defmfun $gf_jacobi
(a b
)
3280 (gf-char?
"gf_jacobi")
3281 (let* ((*ef-arith?
*)
3285 (if (null (gf-rem x y
)) 0 1)
3286 (gf-jacobi x y
*gf-char
*) )))
3288 (defmfun $ef_jacobi
(a b
)
3289 (ef-gf-field?
"ef_jacobi")
3290 (let* ((*ef-arith?
* t
)
3293 (if (= 2 (car (cfactorw *gf-card
*)))
3294 (if (null (gf-rem x y
)) 0 1)
3295 (gf-jacobi x y
*gf-card
*) )))
3297 (defun gf-jacobi (u v q
)
3298 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3299 (if (null (setq u
(gf-rem u v
))) 0
3301 (s (if (evenp (car v
)) 1 (gf-cjacobi c
))) )
3305 (setq u
(gf-xctimes u
(gf-cinv c
)))
3306 (when (every #'oddp
(list (ash (1- q
) -
1) (car u
) (car v
)))
3308 (* s
(gf-jacobi v u q
)) )))))
3310 (defun gf-cjacobi (c)
3312 (let ((*ef-arith?
*)) (gf-jacobi (gf-n2x c
) *gf-red
* *gf-char
*))
3313 ($jacobi c
*gf-char
*) ))
3316 ;; modular composition (uses Horner and square and multiply)
3319 (defmfun $gf_compose
(a b
)
3320 (gf-red?
"gf_compose")
3321 (let ((*ef-arith?
*))
3322 (gf-x2p (gf-compose (gf-p2x a
) (gf-p2x b
) *gf-red
*)) ))
3324 (defmfun $ef_compose
(a b
)
3325 (ef-red?
"ef_compose")
3326 (let ((*ef-arith?
* t
))
3327 (gf-x2p (gf-compose (gf-p2x a
) (gf-p2x b
) *ef-red
*)) ))
3329 (defun gf-compose (x y red
)
3330 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3332 ((or (null x
) (null y
)) nil
)
3335 (let ((n (gf-at y
(cadr x
))))
3336 (if (= 0 n
) nil
(list 0 n
)) ))
3339 (setq res
(gf-nplus res
(list 0 (cadr y
))))
3340 (when (null (cddr y
))
3341 (return (gf-times res
(gf-pow x
(car y
) red
) red
)) )
3342 (setq res
(gf-times res
(gf-pow x
(- (car y
) (caddr y
)) red
) red
)
3345 ;; a(n) with poly a and integer n
3347 (defun gf-at-errchk (n fun
)
3348 (unless (integerp n
)
3349 (gf-merror (intl:gettext
"`~m': Second argument must be an integer.") fun
) ))
3351 (defmfun $gf_at
(a n
) ;; integer n
3353 (gf-at-errchk n
"gf_at")
3354 (let ((*ef-arith?
*))
3355 (gf-at (gf-p2x a
) n
) ))
3357 (defmfun $ef_at
(a n
) ;; poly a, integer n
3358 (ef-gf-field?
"ef_at")
3359 (gf-at-errchk n
"ef_at")
3360 (let ((*ef-arith?
* t
))
3361 (gf-at (gf-p2x a
) n
) ))
3363 (defun gf-at (x n
) ;; Horner and square and multiply
3364 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3365 (if (or (null x
) (integerp x
)) x
3366 (maybe-char-is-fixnum-let ((n n
))
3368 (setq i
(gf-cplus-b i
(cadr x
)))
3369 (when (null (cddr x
))
3370 (setq i1
(gf-cpow n
(the fixnum
(car x
))))
3371 (return (gf-ctimes i i1
)) )
3372 (setq i1
(gf-cpow n
(- (the fixnum
(car x
)) (the fixnum
(caddr x
))))
3376 ;; find a primitive element:
3378 (defmfun $gf_primitive
()
3379 (gf-data?
"gf_primitive")
3380 (let ((*ef-arith?
*))
3382 ((null *gf-prim
*) nil
)
3383 ((equal *gf-prim
* '$unknown
)
3384 (setq *gf-prim
* (gf-prim))
3385 (unless (null *gf-prim
*) (gf-x2p *gf-prim
*)) )
3386 (t (gf-x2p *gf-prim
*)) )))
3388 (defmfun $ef_primitive
()
3389 (ef-data?
"ef_primitive")
3390 (let ((*ef-arith?
* t
))
3392 ((null *ef-prim
*) nil
)
3393 ((equal *ef-prim
* '$unknown
)
3396 (setq *ef-prim
* (let ((*ef-arith?
*)) (gf-x2n *gf-prim
*))) )
3398 (setq *ef-prim
* (ef-prim))
3399 (unless (null *ef-prim
*) (gf-x2p *ef-prim
*)) )))
3400 (t (gf-x2p *ef-prim
*)) )))
3404 (*f-prim
*gf-char
* *gf-exp
* #'gf-prim-p
) )
3407 (*f-prim
*gf-card
* *ef-exp
* #'ef-prim-p
) )
3409 (defun *f-prim
(inc e prim-p-fn
)
3410 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3411 (setq inc
(min $gf_coeff_limit inc
))
3413 (n-lim (expt inc e
))
3416 (when (= $gf_coeff_limit inc
) '$unknown
) )
3417 (setq x
(let ((*gf-char
* inc
)) (gf-n2x n
)))
3420 (setq n
(1- (* (ash n -
1) inc
))) ) ;; go to next monic poly
3421 ((funcall prim-p-fn x
)
3425 ;; precomputation for *f-prim-p:
3427 (defun gf-precomp ()
3428 (*f-precomp
(1- *gf-char
*) *gf-ord
* *gf-fs-ord
*) )
3430 (defun ef-precomp ()
3431 (*f-precomp
(1- *gf-card
*) *ef-ord
* *ef-fs-ord
*) )
3433 (defun *f-precomp
(q-1 ord fs-ord
)
3434 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3439 (sort (get-factor-list q-1
) #'< :key
#'car
) ) ;; .. [pi, ei] ..
3441 (setq fs-ord
(remove-if #'(lambda (sj) (= (car fj
) (car sj
))) fs-ord
:count
1)) )
3443 (mapcar #'(lambda (pe) (list (car pe
) t
(truncate q-1
(car pe
)))) fs-q-1
) );; .. [pi, true, (p-1)/pi] ..
3445 (mapcar #'(lambda (pe) (list (car pe
) nil
)) fs-ord
) ) ;; .. [pi, false] ..
3447 (merge 'list fs-q-1 fs-ord
#'(lambda (a b
) (< (car a
) (car b
)))) )
3450 (setq *ef-fsx
* (apply #'vector fs-list
))
3451 (setq *ef-fsx-base-q
*
3453 (mapcar #'(lambda (pe) (nreverse (gf-n2l (truncate ord
(car pe
))))) ;; qi = ord/pi = sum(aij*p^j, j,0,m)
3455 (setq *ef-x^q-powers
* (gf-x^p-powers
*gf-card
* *ef-exp
* *ef-red
*)) ) ;; x^p^j
3457 (setq *gf-fsx
* (apply #'vector fs-list
))
3458 (setq *gf-fsx-base-p
*
3460 (mapcar #'(lambda (pe) (nreverse (gf-n2l (truncate ord
(car pe
))))) ;; qi = ord/pi = sum(aij*p^j, j,0,m)
3462 (setq *gf-x^p-powers
* (gf-x^p-powers
*gf-char
* *gf-exp
* *gf-red
*)) )))) ;; x^p^j
3464 ;; returns an array of polynomials x^p^j, j = 0, 1, .. , (n-1), where n = *gf-exp*
3466 (defun gf-x^p-powers
(q n red
)
3467 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3468 (declare (integer q
) (fixnum n
))
3469 (let ((a (make-array n
:element-type
'list
:initial-element nil
)) )
3470 (setf (svref a
0) (list 1 1)) ;; x
3473 (declare (fixnum j
))
3474 (setf (svref a j
) (gf-pow (svref a
(1- j
)) q red
)) )))
3476 ;; -----------------------------------------------------------------------------
3479 ;; Primitive polynomials -------------------------------------------------------
3482 ;; test if a is a primitive polynomial over Fq
3484 (defmfun $gf_primitive_poly_p
(a &optional p
)
3486 (p (unless (and (integerp p
) (primep p
))
3487 (gf-merror (intl:gettext
"`gf_primitive_poly_p': ~m is not a prime number.") p
) ))
3488 (t (gf-char?
"gf_primitive_poly_p")
3489 (setq p
*gf-char
*) ))
3490 (let* ((*ef-arith?
*)
3492 (y (gf-p2x a
)) ;; gf-p2x depends on *gf-char*
3494 (gf-primpoly-p y p n
) ))
3496 (defmfun $ef_primitive_poly_p
(y)
3497 (ef-gf-field?
"ef_primitive_poly_p")
3498 (let ((*ef-arith?
* t
))
3500 (gf-primpoly-p y
*gf-card
* (car y
)) ))
3504 ;; TOM HANSEN AND GARY L. MULLEN
3505 ;; PRIMITIVE POLYNOMIALS OVER FINITE FIELDS
3506 ;; (gf-primpoly-p performs a full irreducibility check
3507 ;; and therefore doesn't check whether x^((q^n-1)/(q-1)) = (-1)^n * y(0) mod y)
3509 (defun gf-primpoly-p (y q n
)
3510 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3511 (declare (fixnum n
))
3512 (unless (= 1 (cadr y
)) ;; monic poly assumed
3513 (return-from gf-primpoly-p
) )
3514 (prog* ((fs-q (cfactorw q
))
3515 (*gf-char
* (car fs-q
))
3516 (*gf-exp
* (if *ef-arith?
* (cadr fs-q
) n
))
3520 ;; the constant part ...
3521 (unless (= 0 (car const
)) (return nil
))
3522 (setq const
(cadr const
))
3523 (when (oddp n
) (setq const
(gf-cminus-b const
))) ;; (-1)^n*const
3524 ;; ... must be primitive in Fq:
3525 (unless (if (and *ef-arith?
* (> *gf-exp
* 1))
3526 (let ((*ef-arith?
*)) (gf-prim-p (gf-n2x const
)))
3528 (setq fs-q-1
(sort (mapcar #'car
(get-factor-list q-1
)) #'<))
3529 (zn-primroot-p const q q-1 fs-q-1
) ))
3532 (when (= n
1) (return t
))
3533 ;; y must be irreducible:
3534 (unless (gf-irr-p y q n
) (return nil
))
3535 ;; check for all prime factors fi of r = (q^n-1)/(q-1) which do not divide q-1
3536 ;; that x^(r/fi) mod y is not an integer:
3537 (let (x^q-powers r fs-r fs-r-base-q
)
3539 (setq x^q-powers
(gf-x^p-powers q n y
)
3540 r
(truncate (1- (expt q n
)) q-1
)
3541 fs-r
(sort (mapcar #'car
(get-factor-list r
)) #'<) )
3543 (setq fs-q-1
(sort (mapcar #'car
(get-factor-list q-1
)) #'<)) )
3545 (setq fs-r
(delete-if #'(lambda (sj) (= fj sj
)) fs-r
:count
1)) )
3547 (let ((*gf-char
* q
))
3549 (mapcar #'(lambda (f) (nreverse (gf-n2l (truncate r f
)))) fs-r
) )))
3551 (return (gf-primpoly-p-exit y fs-r-base-q x^q-powers
)) )))
3553 ;; uses exponentiation by pre-computation
3554 (defun gf-primpoly-p-exit (y fs-r-base-q x^q-powers
)
3555 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3556 (do ((i 0 (1+ i
)) (j 0 0) (dim (array-dimension fs-r-base-q
0)) z zz
)
3558 (declare (fixnum i j dim
))
3559 (setq zz
(list 0 1))
3560 (dolist (aij (svref fs-r-base-q i
)) ;; fi = sum(aij*q^j, j,0,n-1)
3561 (setq z
(gf-pow (svref x^q-powers j
) aij y
)
3562 zz
(gf-times zz z y
)
3564 (when (= 0 (car zz
)) (return nil
)) ))
3567 ;; find a primitive polynomial
3569 (defmfun $gf_primitive_poly
(p n
)
3570 (unless (and (integerp p
) (primep p
) (integerp n
))
3571 (gf-merror (intl:gettext
"`gf_primitive_poly' needs a prime number and an integer.")) )
3573 (let ((*ef-arith?
*) (*gf-char
* p
)) ;; gf-x2p needs *gf-char*
3574 (gf-x2p (gf-primpoly p n
)) ))
3576 (defmfun $ef_primitive_poly
(n)
3577 (ef-gf-field?
"ef_primitive_poly")
3578 (let ((*ef-arith?
* t
))
3579 (gf-x2p (gf-primpoly *gf-card
* n
)) ))
3582 (defun gf-primpoly (q n
)
3583 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3584 (declare (fixnum n
))
3585 (let* ((fs-q (cfactorw q
))
3586 (*gf-char
* (car fs-q
))
3587 (*gf-exp
* (if *ef-arith?
* (cadr fs-q
) n
))
3590 (fs-q-1 (sort (mapcar #'car
(get-factor-list q-1
)) #'<))
3591 r fs-r fs-r-base-q
)
3594 (let ((prt (if (= q
2) 1 (zn-primroot q q-1 fs-q-1
))))
3595 (return-from gf-primpoly
3596 (list 1 1 0 (gf-cminus-b prt
)) )))
3597 ;; pre-computation part 1:
3598 (setq r
(truncate (1- (expt q n
)) q-1
)
3599 fs-r
(sort (mapcar #'car
(get-factor-list r
)) #'<) )
3601 (setq fs-r
(delete-if #'(lambda (sj) (= fj sj
)) fs-r
:count
1)) )
3603 (let ((*gf-char
* q
))
3605 (mapcar #'(lambda (f) (nreverse (gf-n2l (truncate r f
)))) fs-r
) )))
3607 (let* ((inc (min $gf_coeff_limit q
))
3608 (i-lim (expt inc n
))
3610 (do ((i (1+ inc
) (1+ i
)))
3612 (gf-merror (intl:gettext
"No primitive polynomial found.~%~\
3613 `gf_coeff_limit' might be too small.~%" )) )
3614 (setq x
(let ((*gf-char
* inc
)) (gf-n2x i
))
3615 x
(cons n
(cons 1 x
)) )
3616 (when (gf-primpoly-p2 x
*gf-char
* *gf-exp
* q n fs-q-1 fs-r-base-q
)
3619 (defun gf-primpoly-p2 (y p e q n fs-q-1 fs-r-base-q
)
3620 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3621 (declare (fixnum e n
))
3622 (when (= 1 (cadr y
)) ;; monic poly assumed
3623 (prog* ((*gf-char
* p
) (*gf-exp
* e
) (q-1 (1- q
))
3624 (const (last y
2)) )
3625 ;; the constant part ...
3626 (unless (= 0 (car const
)) (return nil
))
3627 (setq const
(cadr const
))
3628 (when (oddp n
) (setq const
(gf-cminus-b const
))) ;; (-1)^n*const
3629 ;; ... must be primitive in Fq:
3630 (unless (if (and *ef-arith?
* (> *gf-exp
* 1))
3631 (let ((*ef-arith?
*)) (gf-prim-p (gf-n2x const
)))
3632 (zn-primroot-p const q q-1 fs-q-1
) )
3634 ;; y must be irreducible:
3635 (unless (gf-irr-p y q n
) (return nil
))
3636 ;; y dependent pre-computation and final check:
3637 (return (gf-primpoly-p-exit y fs-r-base-q
(gf-x^p-powers q n y
))) )))
3639 ;; -----------------------------------------------------------------------------
3642 ;; random elements -------------------------------------------------------------
3645 ;; Produces a random element within the given environment
3647 (defmfun $gf_random
(&optional p n
)
3648 (let ((*ef-arith?
* t
))
3650 (n (let ((*gf-char
* p
))
3651 (unless *gf-red?
* (gf-set-rat-header))
3652 (gf-x2p (gf-random p n
)) ))
3653 (t (gf-data?
"gf_random")
3654 (gf-x2p (gf-random *gf-char
* *gf-exp
*)) ))))
3656 (defmfun $ef_random
(&optional q n
)
3657 (let ((*ef-arith?
* t
))
3659 (n (let ((*gf-char
* q
)) (gf-x2p (gf-random q n
))))
3660 (t (ef-data?
"ef_random")
3661 (gf-x2p (gf-random *gf-card
* *ef-exp
*)) ))))
3663 (defun gf-random (q n
)
3664 (do ((e 0 (1+ e
)) c x
)
3668 (setq x
(cons e
(cons c x
))) )))
3670 ;; -----------------------------------------------------------------------------
3673 ;; factoring -------------------------------------------------------------------
3676 (defmfun $gf_factor
(a &optional p
) ;; set p to switch to another modulus
3678 (p (unless (and (integerp p
) (primep p
))
3679 (gf-merror (intl:gettext
"`gf_factor': Second argument must be a prime number.")) )
3680 (gf-set-rat-header) )
3681 (t (gf-char?
"gf_factor")
3682 (setq p
*gf-char
*) ))
3683 (let* ((*gf-char
* p
)
3684 (modulus p
) (a ($rat a
))
3686 (when (> (length (caddar a
)) 1)
3687 (gf-merror (intl:gettext
"`gf_factor': Polynomial must be univariate.")) )
3690 ((integerp a
) (mod a
*gf-char
*))
3692 (if $gf_cantor_zassenhaus
3693 (gf-factor (gf-mod (cdr a
)) p
)
3694 (gf-ns2pmod-factors (pfactor a
)) ))
3695 (setq a
(gf-disrep-factors a
))
3696 (and (consp a
) (consp (car a
)) (equal (caar a
) 'mtimes
)
3697 (setq a
(simplifya (cons '(mtimes) (cdr a
)) nil
)) )
3700 ;; adjust results from rat3d/pfactor to a positive modulus if $gf_balanced = false
3701 (defun gf-ns2pmod-factors (fs) ;; modifies fs
3703 (maybe-char-is-fixnum-let ((m *gf-char
*))
3704 (do ((r fs
(cddr r
)))
3706 (if (integerp (car r
))
3707 (when (< (the integer
(car r
)) 0)
3708 (incf (car r
) m
) ) ;; only in the case *ef-arith?* = false
3709 (rplaca r
(gf-ns2pmod-factor (cdar r
) m
)) )))))
3711 (defun gf-ns2pmod-factor (fac m
)
3712 (do ((r (cdr fac
) (cddr r
))) (())
3713 (when (< (the integer
(car r
)) 0)
3715 (when (null (cdr r
)) (return fac
)) ))
3717 (defun gf-disrep-factors (fs)
3719 ((integerp fs
) (gf-cp2smod fs
))
3721 (setq fs
(nreverse fs
))
3723 ((null fs
) (cons '(mtimes simp factored
) p
))
3724 (declare (fixnum e
))
3725 (setq e
(the fixnum
(car fs
))
3729 ((integerp fac
) (cons (gf-cp2smod fac
) p
))
3730 ((= 1 e
) (cons (gf-disrep (gf-np2smod fac
)) p
))
3731 (t (cons `((mexpt simp
) ,(gf-disrep (gf-np2smod fac
)) ,e
) p
)) ))))))
3733 (defmfun $ef_factor
(a)
3734 (ef-gf-field?
"ef_factor")
3735 (let ((*ef-arith?
* t
))
3736 (setq a
(let ((modulus)) ($rat a
)))
3737 (when (> (length (caddar a
)) 1)
3738 (gf-merror (intl:gettext
"`ef_factor': Polynomial must be univariate.")) )
3741 ((integerp a
) (ef-cmod a
))
3744 (gf-factor (gf-mod (cdr a
)) *gf-card
*) ))
3745 (and (consp a
) (consp (car a
)) (equal (caar a
) 'mtimes
)
3746 (setq a
(simplifya (cons '(mtimes) (cdr a
)) nil
)) )
3749 (defun gf-factor (x q
) ;; non-integer x
3750 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3751 (let ((lc (cadr x
)) z
)
3753 (setq x
(gf-xctimes x
(gf-cinv lc
))) ) ;; monicize x
3754 (if (gf-irr-p x q
(car x
))
3756 (let ((sqfr (gf-square-free x
)) e y
)
3760 y
(gf-distinct-degree-factors y q
) )
3762 (setq z
(nconc (gf-equal-degree-factors w q e
) z
)) ))))
3763 (if (= 1 lc
) z
(cons lc
(cons 1 z
))) ))
3766 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3768 (maybe-char-is-fixnum-let ((m *gf-char
*))
3769 (do ((rx x
(cddr rx
)) res c
)
3770 ((or (null rx
) (= 0 (car rx
))) (nreverse res
))
3771 (setq c
(gf-ctimes (mod (the fixnum
(car rx
)) m
) (cadr rx
)))
3773 (push (1- (car rx
)) res
)
3777 (defun ef-pth-croot (c)
3778 (let ((p *gf-char
*) (*ef-arith?
* t
))
3779 (dotimes (i (1- *gf-exp
*) c
)
3780 (setq c
(gf-cpow c p
)) )))
3782 (defun gf-pth-root (x)
3783 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3784 (maybe-char-is-fixnum-let ((p *gf-char
*))
3786 (do ((rx x
(cddr rx
)) res c
)
3787 ((null rx
) (nreverse res
))
3788 (push (truncate (the fixnum
(car rx
)) p
) res
)
3790 (when *ef-arith?
* ;; p # q
3791 (setq c
(ef-pth-croot c
)) )
3794 (defun gf-gcd-cofactors (x dx
)
3795 (let ((g (gf-gcd x dx
)))
3796 (values g
(gf-divide x g
) (gf-divide dx g
)) ))
3798 (defun gf-square-free (x) ;; monic x
3799 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3800 (let (f fs
(r (gf-diff x
)) g
)
3802 ((equal '(0 1) (setq g
(gf-gcd x r
))) `((1 ,x
)))
3805 (setq r
(gf-divide x g
)
3809 (declare (fixnum m
))
3810 (multiple-value-setq (r f x
) (gf-gcd-cofactors r x
))
3811 (unless (equal '(0 1) f
)
3812 (push (list m f
) fs
) )))
3813 (unless (equal '(0 1) x
)
3815 (append (mapcar #'(lambda (v) (rplaca v
(* (car v
) *gf-char
*)))
3816 (gf-square-free (gf-pth-root x
)) )
3820 (defun gf-distinct-degree-factors (x q
)
3821 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3822 (let ((w '(1 1)) f fs
(*gf-char
* (car (cfactorw q
))) )
3824 ((equal '(0 1) x
) fs
)
3825 (declare (fixnum n
))
3826 (when (> (ash n
1) (car x
))
3827 (setq fs
(cons (list x
(car x
)) fs
))
3829 (setq w
(gf-nred w x
)
3831 f
(gf-gcd (gf-plus w
(gf-nminus (list 1 1))) x
) )
3832 (unless (equal '(0 1) f
)
3833 (setq fs
(cons (list f n
) fs
)
3834 x
(gf-divide x f
) )))
3837 (defun gf-nonconst-random (q q^n
)
3839 (setq r
(random q^n
))
3840 (when (>= r q
) (return (let ((*gf-char
* q
)) (gf-n2x r
)))) ))
3842 ;; computes Tm(x) = x^2^(m-1) + x^2^(m-2) + .. + x^4 + x^2 + x in F2[x]
3844 (defun gf-trace-poly-f2 (x m red
) ;; m > 0
3845 (let ((tm (gf-nred x red
)))
3848 (declare (fixnum i
))
3849 (setq x
(gf-sq x red
)
3850 tm
(gf-plus tm x
) ))))
3852 ;; Cantor and Zassenhaus' algorithm
3854 (defun gf-equal-degree-factors (x-and-d q mult
)
3855 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3856 (let* ((x (car x-and-d
)) (d (cadr x-and-d
))
3858 (declare (fixnum d n
))
3860 ((= n d
) (list x mult
))
3862 (let* ((p^k
(cfactorw q
)) (p (car p^k
)) (k (cadr p^k
)) (*gf-char
* p
)
3863 (f '(0 1)) (q^n
(expt q n
)) m e r r^e
)
3865 (setq m
(* k d
)) ;; q = 2^k
3866 (setq e
(ash (1- (expt q d
)) -
1)) )
3868 (do () ((and (not (equal '(0 1) f
)) (not (equal x f
))))
3869 (setq r
(gf-nonconst-random q q^n
)
3871 (when (equal '(0 1) f
)
3873 (if (= 2 p
) (gf-trace-poly-f2 r m x
) ;; q = 2^k
3874 (gf-pow r e x
) )) ;; q is odd prime power
3875 (setq f
(gf-gcd x
(gf-nplus r^e
(gf-nminus (list 0 1))))) ))
3877 (append (gf-equal-degree-factors (list (gf-divide x f
) d
) q mult
)
3878 (gf-equal-degree-factors (list f d
) q mult
) ))))))
3880 ;; -----------------------------------------------------------------------------
3883 ;; gcd, gcdex and test of invertibility ----------------------------------------
3886 (defmfun $ef_gcd
(a b
)
3887 (ef-gf-field?
"ef_gcd")
3888 (let ((*ef-arith?
* t
))
3889 (gf-x2p (gf-gcd (gf-p2x a
) (gf-p2x b
))) ))
3891 (defmfun $gf_gcd
(a b
&optional p
)
3892 (let ((*ef-arith?
*))
3894 (p (unless (and (integerp p
) (primep p
))
3895 (gf-merror (intl:gettext
"`gf_gcd': ~m is not a prime number.") p
) )
3897 (let* ((*gf-char
* p
)
3899 (vars (caddar ($rat a
))) )
3900 (when (> (length vars
) 1)
3901 (gf-merror (intl:gettext
"`gf_gcd': Polynomials must be univariate.")) )
3902 (gf-x2p (gf-gcd (gf-p2x a
) (gf-p2x b
))) ))
3903 (t (gf-char?
"gf_gcd")
3904 (gf-x2p (gf-gcd (gf-p2x a
) (gf-p2x b
))) ))))
3907 (defmfun $gf_gcdex
(a b
)
3908 (gf-red?
"gf_gcdex")
3909 (let ((*ef-arith?
*))
3911 (mapcar #'gf-x2p
(gf-gcdex (gf-p2x a
) (gf-p2x b
) *gf-red
*)) )))
3913 (defmfun $ef_gcdex
(a b
)
3914 (ef-red?
"ef_gcdex")
3915 (let ((*ef-arith?
* t
))
3917 (mapcar #'gf-x2p
(gf-gcdex (gf-p2x a
) (gf-p2x b
) *gf-red
*)) )))
3920 (defmfun $gf_unit_p
(a)
3921 (gf-red?
"gf_unit_p")
3922 (let ((*ef-arith?
*))
3923 (gf-unit-p (gf-p2x a
) *gf-red
*) ))
3925 (defmfun $ef_unit_p
(a)
3926 (ef-red?
"ef_unit_p")
3927 (let ((*ef-arith?
* t
))
3928 (gf-unit-p (gf-p2x a
) *ef-red
*) ))
3930 (defun gf-unit-p (x red
)
3931 (= 0 (car (gf-gcd x red
))) )
3933 ;; -----------------------------------------------------------------------------
3936 ;; order -----------------------------------------------------------------------
3939 ;; group/element order
3941 (defmfun $gf_order
(&optional a
)
3942 (gf-data?
"gf_order")
3944 (a (let ((*ef-arith?
*))
3946 (when (and a
(or *gf-irred?
* (gf-unit-p a
*gf-red
*)))
3947 (gf-ord a
*gf-ord
* *gf-fs-ord
* *gf-red
*) )))
3950 (defmfun $ef_order
(&optional a
)
3951 (ef-data?
"ef_order")
3953 (a (let ((*ef-arith?
* t
))
3955 (when (and a
(or *ef-irred?
* (gf-unit-p a
*ef-red
*)))
3956 (gf-ord a
*ef-ord
* *ef-fs-ord
* *ef-red
*) )))
3959 ;; find the lowest value k for which a^k = 1
3961 (defun gf-ord (x ord fs-ord red
) ;; assume x # 0
3962 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3964 (declare (fixnum e
))
3965 (dolist (pe fs-ord ord
)
3967 e
(the fixnum
(cadr pe
))
3968 ord
(truncate ord
(expt p e
))
3969 z
(gf-pow$ x ord red
) ) ;; use exponentiation by precomputation
3972 (setq ord
(* ord p
))
3973 (when (= e
1) (return))
3975 (setq z
(gf-pow$ z p red
)) ))))
3977 (defun gf-ord-by-table (x)
3978 (let ((index (svref $gf_logs
(gf-x2n x
))))
3979 (truncate *gf-ord
* (gcd *gf-ord
* index
)) ))
3982 ;; Fq^n = F[x]/(f) is no field <=> f splits into factors
3984 ;; f = f1^e1 * ... * fk^ek where fi are irreducible of degree ni.
3986 ;; We compute the order of the group (F[x]/(fi^ei))* by
3988 ;; ((q^ni)^ei - (q^ni)^(ei-1)) = ((q^ni) - 1) * (q^ni)^(ei-1)
3990 ;; and ord((Fq^n)*) with help of the Chinese Remainder Theorem.
3992 (defun gf-group-order (q red
)
3993 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
3994 (let (ne-list q^n
(e 0) (ord 1))
3995 (declare (fixnum e
))
3996 (do ((x (gf-factor red q
))) ;; red is assumed to be a monic poly
3998 (push (list (caar x
) (cadr x
)) ne-list
) ;; (list ni ei), f = prod(fi^ei) with fi of degree ni
4001 (setq q^n
(expt q
(the fixnum
(car a
)))
4002 e
(the fixnum
(cadr a
))
4003 ord
(* ord
(1- q^n
) (expt q^n
(the fixnum
(1- e
)))) ))
4006 ;; -----------------------------------------------------------------------------
4009 ;; degree, minimal polynomial, trace and norm ----------------------------------
4013 ;; degree: Find the lowest value d for which x^(q^d) = x
4015 (defun gf-degree-errchk (a n fun
)
4016 (when (and (not (null a
)) (>= (car a
) n
))
4017 (gf-merror (intl:gettext
"`~m': Leading exponent must be smaller than ~m.") fun n
) ))
4019 (defmfun $gf_degree
(a)
4020 (gf-field?
"gf_degree")
4021 (let ((*ef-arith?
*))
4023 (gf-degree-errchk a
*gf-exp
* "gf_degree")
4024 (*f-deg a
*gf-exp
* *gf-red
* *gf-x^p-powers
*) ))
4026 (defmfun $ef_degree
(a)
4027 (ef-field?
"ef_degree")
4028 (let ((*ef-arith?
* t
))
4030 (gf-degree-errchk a
*ef-exp
* "ef_degree")
4031 (*f-deg a
*ef-exp
* *ef-red
* *ef-x^q-powers
*) ))
4033 (defun *f-deg
(x n red x^q-powers
)
4036 (declare (fixnum d
))
4037 (when (equal x
(gf-compose (svref x^q-powers d
) x red
)) ;; f(x)^q = f(x^q)
4041 ;; produce the minimal polynomial
4043 (defmfun $gf_minimal_poly
(a)
4044 (gf-field?
"gf_minimal_poly")
4045 (let ((*ef-arith?
*))
4047 (gf-degree-errchk a
*gf-exp
* "gf_minimal_poly")
4048 (gf-minpoly a
*gf-red
* *gf-x^p-powers
*) ))
4050 (defmfun $ef_minimal_poly
(a)
4051 (ef-field?
"ef_minimal_poly")
4052 (let ((*ef-arith?
* t
))
4054 (gf-degree-errchk a
*ef-exp
* "ef_minimal_poly")
4055 (gf-minpoly a
*ef-red
* *ef-x^q-powers
*) ))
4059 ;; f(z) = (z - x) (z - x ) (z - x ) ... (z - x ) , where d = degree(x)
4061 (defun gf-minpoly (x red x^q-powers
)
4064 (powers (list (gf-minus x
)))
4065 (prod (list 0 (list 0 1)))
4066 xqi zx cx
) (declare (fixnum n
))
4068 ((= i n
)) (declare (fixnum i
))
4069 (setq xqi
(gf-compose (svref x^q-powers i
) x red
))
4070 (when (equal x xqi
) (return))
4071 (push (gf-nminus xqi
) powers
) )
4072 (dolist (pow powers
)
4073 (setq zx
(gf-zx prod
)
4074 cx
(gf-ncx pow prod red
)
4075 prod
(gf-nzx+cx zx cx
)) )
4076 ($substitute
'$z
'$x
(gf-x2p (gf-nxx2x prod
))) )))
4078 (defun gf-zx (x) ;; (gf-zx '(3 (5 1 3 1) 2 (4 1))) -> (4 (5 1 3 1) 3 (4 1))
4079 ;; 3 5 3 2 4 4 5 3 3 4
4080 ;; z (x + x ) + z x -> z (x + x ) + z x
4081 (do* ((res (list (1+ (car x
)) (cadr x
)))
4082 (r (cdr res
) (cddr r
))
4083 (rx (cddr x
) (cddr rx
)) )
4085 (rplacd r
(list (1+ (car rx
)) (cadr rx
))) ))
4087 (defun gf-ncx (c x red
) ;; modifies x
4088 ;; (gf-ncx '(1 1) '(3 (4 1 3 1) 2 (2 1)) '(6 1))
4089 ;; -> (3 (5 1 4 1) 2 (3 1))
4091 (do ((r (cdr x
) (cddr r
)))
4093 (rplaca r
(gf-times c
(car r
) red
)) )))
4095 (defun gf-nzx+cx
(zx cx
) ;; modifies zx
4097 (s (cdr cx
) (cddr s
)) r
+s
)
4098 ((null (cdr r
)) (nconc zx
(list 0 (car s
))))
4099 (setq r
+s
(gf-plus (caddr r
) (car s
)))
4101 (rplaca (setq r
(cddr r
)) r
+s
)
4102 (rplacd r
(cdddr r
)) )))
4104 (defun gf-nxx2x (xx) ;; modifies xx
4105 ;; (gf-nxx2x '(4 (0 3) 2 (0 1))) -> (4 3 2 1)
4106 (do ((r (cdr xx
) (cddr r
)))
4108 (rplaca r
(cadar r
)) ))
4113 ;; trace(a) = a + a + a + .. + a
4115 (defmfun $gf_trace
(a)
4116 (gf-field?
"gf_trace")
4117 (let ((*ef-arith?
*))
4118 (gf-trace (gf-p2x a
) *gf-red
* *gf-x^p-powers
*) ))
4120 (defmfun $ef_trace
(a)
4121 (ef-field?
"ef_trace")
4122 (let ((*ef-arith?
* t
))
4123 (gf-trace (gf-p2x a
) *ef-red
* *ef-x^q-powers
*) ))
4125 (defun gf-trace (x red x^q-powers
)
4129 ((= i n
) (gf-x2p su
)) (declare (fixnum i
))
4130 (setq su
(gf-plus su
(gf-compose (svref x^q-powers i
) x red
))) )))
4133 ;; 2 (n-1) n 2 (n-1)
4134 ;; 1 + q + q + .. + q (q - 1)/(q - 1) q q q
4135 ;; norm(a) = a = a = a * a * a * .. * a
4137 (defmfun $gf_norm
(a)
4138 (gf-field?
"gf_norm")
4139 (let ((*ef-arith?
*))
4140 (gf-norm (gf-p2x a
) *gf-red
* *gf-x^p-powers
*) ))
4142 (defmfun $ef_norm
(a)
4143 (ef-field?
"ef_norm")
4144 (let ((*ef-arith?
* t
))
4145 (gf-norm (gf-p2x a
) *ef-red
* *ef-x^q-powers
*) ))
4147 (defun gf-norm (x red x^q-powers
)
4151 ((= i n
) (gf-x2p prod
)) (declare (fixnum i
))
4152 (setq prod
(gf-times prod
(gf-compose (svref x^q-powers i
) x red
) red
)) )))
4154 ;; -----------------------------------------------------------------------------
4157 ;; normal elements and normal basis --------------------------------------------
4160 ;; Tests if an element is normal
4162 (defmfun $gf_normal_p
(a)
4163 (gf-field?
"gf_normal_p")
4164 (let ((*ef-arith?
*)) (gf-normal-p (gf-p2x a
))) )
4166 (defun gf-normal-p (x)
4168 (let ((modulus *gf-char
*)
4169 (mat (gf-maybe-normal-basis x
)) )
4170 (equal ($rank mat
) *gf-exp
*) )))
4172 (defmfun $ef_normal_p
(a)
4173 (ef-field?
"ef_normal_p")
4174 (let ((*ef-arith?
* t
)) (ef-normal-p (gf-p2x a
))) )
4176 (defun ef-normal-p (x)
4178 (let ((mat (ef-maybe-normal-basis x
)) )
4179 (/= 0 ($ef_determinant mat
)) )))
4182 ;; Finds a normal element e in the field; that is,
4183 ;; an element for which the list [e, e^q, e^(q^2), ... , e^(q^(n-1))] is a basis
4185 (defmfun $gf_normal
()
4186 (gf-field?
"gf_normal")
4187 (let ((*ef-arith?
*))
4188 (gf-x2p (gf-normal *gf-char
* *gf-exp
* #'gf-normal-p
)) ))
4190 (defmfun $ef_normal
()
4191 (ef-field?
"ef_normal")
4192 (let ((*ef-arith?
* t
))
4193 (gf-x2p (gf-normal *gf-card
* *ef-exp
* #'ef-normal-p
)) ))
4195 (defun gf-normal (q n normal-p-fn
)
4196 (let* ((inc (min $gf_coeff_limit q
))
4197 (i-lim (expt inc n
))
4199 (do ((i inc
(1+ i
)))
4201 (gf-merror (intl:gettext
"No normal element found.~%~\
4202 `gf_coeff_limit' might be too small.~%" )) )
4203 (setq x
(let ((*gf-char
* inc
)) (gf-n2x i
)))
4204 (when (funcall normal-p-fn x
) (return-from gf-normal x
)) )))
4207 ;; Finds a normal element in the field by producing random elements and checking
4208 ;; if each one is normal
4210 (defmfun $gf_random_normal
()
4211 (gf-field?
"gf_random_normal")
4212 (let ((*ef-arith?
*)) (gf-x2p (gf-random-normal))) )
4214 (defun gf-random-normal ()
4215 (do ((x (gf-random *gf-char
* *gf-exp
*) (gf-random *gf-char
* *gf-exp
*)))
4216 ((gf-normal-p x
) x
) ))
4218 (defmfun $ef_random_normal
()
4219 (ef-field?
"ef_random_normal")
4220 (let ((*ef-arith?
* t
)) (gf-x2p (ef-random-normal))) )
4222 (defun ef-random-normal ()
4223 (do ((x (gf-random *gf-card
* *ef-exp
*) (gf-random *gf-card
* *ef-exp
*)))
4224 ((ef-normal-p x
) x
) ))
4226 ;; Produces a normal basis as a matrix;
4227 ;; the columns are the coefficients of the powers e^(q^i) of the normal element
4229 (defmfun $gf_normal_basis
(a)
4230 (gf-field?
"gf_normal_basis")
4231 (let* ((*ef-arith?
*)
4234 (mat (gf-maybe-normal-basis x
)) )
4235 (unless (equal ($rank mat
) *gf-exp
*)
4236 (gf-merror (intl:gettext
"Argument to `gf_normal_basis' must be a normal element.")) )
4239 (defmfun $ef_normal_basis
(a)
4240 (ef-field?
"ef_normal_basis")
4241 (let* ((*ef-arith?
* t
)
4242 (mat (ef-maybe-normal-basis (gf-p2x a
))) )
4243 (unless (/= 0 ($ef_determinant mat
))
4244 (merror (intl:gettext
"Argument to `ef_normal_basis' must be a normal element." )) )
4247 (defun gf-maybe-normal-basis (x)
4248 (*f-maybe-normal-basis x
*gf-x^p-powers
* *gf-exp
* *gf-red
*) )
4250 (defun ef-maybe-normal-basis (x)
4251 (*f-maybe-normal-basis x
*ef-x^q-powers
* *ef-exp
* *ef-red
*) )
4253 (defun *f-maybe-normal-basis
(x x^q-powers e red
)
4254 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
4255 (declare (fixnum e
))
4256 (let ((e-1 (- e
1))) (declare (fixnum e-1
))
4259 #'(lambda (i j
) (declare (fixnum i j
))
4261 (gf-compose (svref x^q-powers
(1- i
)) x red
) e-1
) (1- j
)))
4264 ;; coefficients as an array of designated length
4266 (defun gf-x2array (x len
)
4267 #+ (or ccl ecl gcl sbcl
) (declare (optimize (speed 3) (safety 0)))
4268 (declare (fixnum len
))
4269 (let ((cs (make-array (1+ len
) :initial-element
0)))
4270 (do ((k len
)) ((null x
) cs
) (declare (fixnum k
))
4272 ((> k
(the fixnum
(car x
)))
4274 ((= k
(the fixnum
(car x
)))
4275 (setf (svref cs
(- len k
)) (cadr x
))
4279 (setq x
(cddr x
)) ) ))))
4281 ;; Produces the normal representation of an element as a list of coefficients
4282 ;; Needs the inverted normal basis as the second argument
4283 ;; (the inversion might be time consuming)
4285 (defmfun $gf_normal_basis_rep
(a m-inv
)
4286 (gf-field?
"gf_normal_basis_rep")
4287 (let ((*ef-arith?
*))
4288 (gf-normal-basis-rep (gf-p2x a
) m-inv
*gf-exp
* '$gf_matmult
) ))
4290 (defmfun $ef_normal_basis_rep
(a m-inv
)
4291 (ef-field?
"ef_normal_basis_rep")
4292 (let ((*ef-arith?
* t
))
4293 (gf-normal-basis-rep (gf-p2x a
) m-inv
*ef-exp
* '$ef_matmult
) ))
4295 (defun gf-normal-basis-rep (x m-inv e matmult-fn
)
4296 (let* ((cs (cons '(mlist simp
) (gf-x2l x e
)))
4297 (nbrep (mfuncall matmult-fn m-inv cs
)) )
4298 (cons '(mlist simp
) (mapcar #'cadr
(cdr nbrep
))) ))
4300 ;; -----------------------------------------------------------------------------
4303 ;; functions for matrices ------------------------------------------------------
4306 (defmfun $gf_matneg
(m)
4307 (gf-char?
"gf_matneg")
4308 (mfuncall '$matrixmap
'$gf_neg m
) )
4310 (defmfun $ef_matneg
(m)
4311 (ef-gf-field?
"ef_matneg")
4312 (mfuncall '$matrixmap
'$ef_neg m
) )
4315 ;; matrix addition (convenience: mat, list or poly possible as argument)
4317 (defmfun $gf_matadd
(&rest args
)
4318 (let ((*ef-arith?
*))
4319 (reduce #'(lambda (m1 m2
) (gf-matadd m1 m2
'$gf_add
)) args
) ))
4321 (defmfun $ef_matadd
(&rest args
)
4322 (gf-data?
"ef_matadd")
4323 (let ((*ef-arith?
* t
))
4324 (reduce #'(lambda (m1 m2
) (gf-matadd m1 m2
'$ef_add
)) args
) ))
4326 (defun gf-matadd (m1 m2 add-fn
)
4327 (when ($listp m1
) (setq m1
($transpose m1
)))
4328 (when ($listp m2
) (setq m2
($transpose m2
)))
4330 ((and ($matrixp m1
) ($matrixp m2
))
4331 (gf-matadd2 m1 m2 add-fn
) )
4333 (gf-matadd1 m1 m2 add-fn
) ) ;; assumed without checking: m2 is poly
4335 (gf-matadd1 m2 m1 add-fn
) )
4337 (mfuncall add-fn m1 m2
) ) ))
4339 (defun gf-matadd1 (m poly add-fn
)
4340 (do ((r (cdr m
) (cdr r
)) new
)
4341 ((null r
) (cons '($matrix simp
) (nreverse new
)))
4342 (push (cons '(mlist simp
)
4343 (mapcar #'(lambda (p) (mfuncall add-fn p poly
)) (cdar r
)) )
4346 (defun gf-matadd2-error ()
4348 (intl:gettext
"Arguments to `~m' must have same formal structure.")
4349 (if *ef-arith?
* "ef_matadd" "gf_matadd") ))
4351 (defun gf-matadd2 (m1 m2 add-fn
)
4352 (setq m1
(cdr m1
) m2
(cdr m2
))
4353 (unless (= (length (car m1
)) (length (car m2
)))
4354 (gf-matadd2-error) )
4355 (do ((r1 m1
(cdr r1
)) (r2 m2
(cdr r2
)) new
)
4356 ((or (null r1
) (null r2
))
4357 (unless (and (null r1
) (null r2
))
4358 (gf-matadd2-error) )
4359 (cons '($matrix simp
) (nreverse new
)) )
4360 (push (cons '(mlist simp
) (mapcar add-fn
(cdar r1
) (cdar r2
))) new
) ))
4363 ;; matrix multiplication (convenience: mat, list or poly possible as argument)
4365 (defmfun $gf_matmult
(&rest args
)
4366 (gf-red?
"gf_matmult")
4367 (let ((*ef-arith?
*))
4368 (apply #'*f-matmult
`($gf_mult
,@args
)) ))
4370 (defmfun $ef_matmult
(&rest args
)
4371 (ef-red?
"ef_matmult")
4372 (let ((*ef-arith?
* t
))
4373 (apply #'*f-matmult
`($ef_mult
,@args
)) ))
4375 (defun *f-matmult
(mult-fn &rest args
)
4377 #'(lambda (m1 m2
) (gf-matmult m1 m2 mult-fn
))
4378 (cons '(mlist simp
) args
) ))
4380 (defun gf-matmult (m1 m2 mult-fn
)
4381 (when ($listp m1
) (setq m1
(list '($matrix simp
) m1
)))
4382 (when ($listp m2
) (setq m2
($transpose m2
)))
4384 ((and ($matrixp m1
) ($matrixp m2
))
4385 (gf-matmult2 m1 m2
) )
4387 (gf-matmult1 m1 m2 mult-fn
) ) ;; assumed without checking: m2 is poly
4389 (gf-matmult1 m2 m1 mult-fn
) )
4391 (mfuncall mult-fn m1 m2
) ) ))
4393 (defun gf-matmult1 (m poly mult-fn
)
4394 (do ((r (cdr m
) (cdr r
)) new
)
4395 ((null r
) (cons '($matrix simp
) (nreverse new
)))
4396 (push (cons '(mlist simp
)
4397 (mapcar #'(lambda (p) (mfuncall mult-fn p poly
)) (cdar r
)) )
4400 (defun gf-matmult2 (m1 m2
)
4401 (setq m1
(cdr m1
) m2
(cdr ($transpose m2
)))
4402 (unless (= (length (car m1
)) (length (car m2
)))
4404 (intl:gettext
"`~m': attempt to multiply non conformable matrices.")
4405 (if *ef-arith?
* "ef_matmult" "gf_matmult") ))
4406 (let ((red (if *ef-arith?
* *ef-red
* *gf-red
*)) )
4407 (do ((r1 m1
(cdr r1
)) new-mat
)
4409 (if (and (not (eq nil $scalarmatrixp
))
4410 (= 1 (length new-mat
)) (= 1 (length (cdar new-mat
))) )
4412 (cons '($matrix simp
) (nreverse new-mat
)) ))
4413 (do ((r2 m2
(cdr r2
)) new-row
)
4415 (push (cons '(mlist simp
) (nreverse new-row
)) new-mat
) )
4418 (mapcar #'(lambda (a b
) (gf-times (gf-p2x a
) (gf-p2x b
) red
))
4419 (cdar r1
) (cdar r2
) )))
4422 ;; -----------------------------------------------------------------------------
4425 ;; invert and determinant by lu ------------------------------------------------
4428 (defun zn-p-errchk (p fun pos
)
4429 (unless (and p
(integerp p
) (primep p
))
4430 (gf-merror (intl:gettext
"`~m': ~m argument must be prime number.") fun pos
) ))
4434 ;; returns nil when LU-decomposition fails
4435 (defun try-lu-and-call (fun m ring
)
4436 (let ((old-out *standard-output
*)
4437 (redirect (make-string-output-stream))
4439 (unwind-protect ;; protect against lu failure
4440 (setq *standard-output
* redirect
;; discard error messages from lu-factor
4441 res
(mfuncall fun m ring
) )
4443 (setq *standard-output
* old-out
)
4445 (return-from try-lu-and-call res
) )))
4447 (defmfun $zn_invert_by_lu
(m p
)
4448 (zn-p-errchk p
"zn_invert_by_lu" "Second")
4449 (let ((*ef-arith?
*) (*gf-char
* p
))
4450 (try-lu-and-call '$invert_by_lu m
'gf-coeff-ring
) ))
4452 (defmfun $gf_matinv
(m)
4453 (format t
"`gf_matinv' is deprecated. ~%~\
4454 The user is asked to use `gf_invert_by_lu' instead.~%" )
4455 ($gf_invert_by_lu m
) )
4457 (defmfun $gf_invert_by_lu
(m)
4458 (gf-field?
"gf_invert_by_lu")
4459 (let ((*ef-arith?
*)) (try-lu-and-call '$invert_by_lu m
'gf-ring
)) )
4461 (defmfun $ef_invert_by_lu
(m)
4462 (ef-field?
"ef_invert_by_lu")
4463 (let ((*ef-arith?
* t
)) (try-lu-and-call '$invert_by_lu m
'ef-ring
)) )
4467 (defmfun $zn_determinant
(m p
)
4468 (zn-p-errchk p
"zn_determinant" "Second")
4469 (let* ((*ef-arith?
*)
4471 (det (try-lu-and-call '$determinant_by_lu m
'gf-coeff-ring
)) )
4473 (mod (mfuncall '$determinant m
) p
) )))
4475 (defmfun $gf_determinant
(m)
4476 (gf-field?
"gf_determinant")
4477 (let* ((*ef-arith?
*)
4478 (det (try-lu-and-call '$determinant_by_lu m
'gf-ring
)) )
4480 (let (($matrix_element_mult
'$gf_mult
) ($matrix_element_add
'$gf_add
))
4481 (mfuncall '$determinant m
) ))))
4483 (defmfun $ef_determinant
(m)
4484 (ef-field?
"ef_determinant")
4485 (let* ((*ef-arith?
* t
)
4486 (det (try-lu-and-call '$determinant_by_lu m
'ef-ring
)) )
4488 (let (($matrix_element_mult
'$ef_mult
) ($matrix_element_add
'$ef_add
))
4489 (mfuncall '$determinant m
) ))))
4491 ;; -----------------------------------------------------------------------------
4494 ;; discrete logarithm ----------------------------------------------------------
4497 ;; solve g^x = a in Fq^n, where g a generator of (Fq^n)*
4499 (defmfun $gf_index
(a)
4500 (gf-data?
"gf_index")
4501 (gf-log-errchk1 *gf-prim
* "gf_index")
4502 (let ((*ef-arith?
*))
4504 ($zn_log a
(gf-x2n *gf-prim
*) *gf-char
*)
4505 (gf-dlog (gf-p2x a
)) )))
4507 (defmfun $ef_index
(a)
4508 (ef-data?
"ef_index")
4509 (gf-log-errchk1 *ef-prim
* "ef_index")
4510 (let ((*ef-arith?
* t
))
4513 (let ((*ef-arith?
*)) (gf-dlog (gf-n2x (cadr a
))))
4516 (defmfun $gf_log
(a &optional b
)
4518 (gf-log-errchk1 *gf-prim
* "gf_log")
4519 (let ((*ef-arith?
*))
4522 ($zn_log a
(if b b
(gf-x2n *gf-prim
*)) *gf-char
*) ) ;; $zn_log checks if b is primitive
4525 (and b
(setq b
(gf-p2x b
)) (gf-log-errchk2 b
#'gf-prim-p
"gf_log"))
4530 (defun gf-log-errchk1 (prim fun
)
4532 (gf-merror (intl:gettext
"`~m': there is no primitive element.") fun
) )
4533 (when (equal prim
'$unknown
)
4534 (gf-merror (intl:gettext
"`~m': a primitive element is not known.") fun
) ))
4536 (defun gf-log-errchk2 (x prim-p-fn fun
)
4537 (unless (funcall prim-p-fn x
)
4538 (gf-merror (intl:gettext
4539 "Second argument to `~m' must be a primitive element." ) fun
)))
4541 (defmfun $ef_log
(a &optional b
)
4543 (gf-log-errchk1 *ef-prim
* "ef_log")
4544 (let ((*ef-arith?
* t
))
4546 (and b
(setq b
(gf-p2x b
)) (gf-log-errchk2 b
#'ef-prim-p
"ef_log")) )
4549 (let ((*ef-arith?
*))
4550 (setq a
(gf-n2x (cadr a
)))
4552 (gf-dlogb a
(gf-n2x (cadr b
)))
4555 (let ((*ef-arith?
* t
))
4560 (defun gf-dlogb (a b
)
4561 (*f-dlogb a b
#'gf-dlog
*gf-ord
*) )
4563 (defun ef-dlogb (a b
)
4564 (*f-dlogb a b
#'ef-dlog
*ef-ord
*) )
4566 (defun *f-dlogb
(a b dlog-fn ord
)
4567 (let* ((a-ind (funcall dlog-fn a
)) (b-ind (funcall dlog-fn b
))
4568 (d (gcd (gcd a-ind b-ind
) ord
))
4569 (m (truncate ord d
)) )
4570 (zn-quo (truncate a-ind d
) (truncate b-ind d
) m
) ))
4572 ;; Pohlig and Hellman reduction
4575 (*f-dlog a
*gf-prim
* *gf-red
* *gf-ord
* *gf-fs-ord
*) )
4578 (*f-dlog a
*ef-prim
* *ef-red
* *ef-ord
* *ef-fs-ord
*) )
4580 (defun *f-dlog
(a g red ord fs-ord
)
4581 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
4583 ((or (null a
) (null g
)) nil
)
4584 ((>= (car a
) (car red
)) nil
)
4585 ((equal '(0 1) a
) 0)
4587 ((not (gf-unit-p a red
)) nil
)
4589 (let (p (e 0) ord
/p om xp xk dlogs mods
(g-inv (gf-inv g red
)))
4590 (declare (fixnum e
))
4592 (setq p
(car f
) e
(cadr f
)
4593 ord
/p
(truncate ord p
)
4594 om
(gf-pow g ord
/p red
)
4596 (do ((b a
) (k 0) (pk 1) (acc g-inv
) (e1 (1- e
)))
4597 (()) (declare (fixnum k
))
4598 (setq xk
(gf-dlog-rho-brent (gf-pow b ord
/p red
) om p red
))
4601 (when (= k e
) (return))
4602 (setq ord
/p
(truncate ord
/p p
)
4604 (when (/= xk
0) (setq b
(gf-times b
(gf-pow acc xk red
) red
)))
4605 (when (/= k e1
) (setq acc
(gf-pow acc p red
))) )
4606 (push (expt p e
) mods
)
4608 (car (solve-congruences dlogs mods
)) ))))
4610 ;; iteration for Pollard rho: b = g^y * a^z in each step
4612 (defun gf-dlog-f (b y z a g p red
)
4613 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
4614 (let ((m (mod (cadr b
) 3))) (declare (fixnum m
))
4617 (values (gf-sq b red
) (mod (ash y
1) p
) (mod (ash z
1) p
)) )
4618 ((= 1 m
) ;; avoid stationary case b=1 => b^2=1
4619 (values (gf-times g b red
) (mod (+ y
1) p
) z
) )
4621 (values (gf-times a b red
) y
(mod (+ z
1) p
) ) ) )))
4625 (defun gf-dlog-naive (a g red
)
4627 (gi '(0 1) (gf-times gi g red
)) )
4630 ;; baby-steps-giant-steps:
4632 (defun gf-dlog-baby-giant (a g p red
) ;; g is generator of order prime p
4633 (let* ((m (1+ (isqrt p
)))
4634 (s (floor (* 1.3 m
)))
4638 (make-hash-table :size s
:test
#'equal
:rehash-threshold
0.9) )
4641 (when (equal '(0 1) b
)
4643 (return-from gf-dlog-baby-giant r
) )
4644 (setf (gethash b babies
) r
)
4646 (when (= r m
) (return))
4647 (setq b
(gf-times gi b red
)) )
4648 (setq g^m
(gf-pow g m red
))
4650 (bb (list 0 1) (gf-times g^m bb red
))
4652 (when (setq r
(gethash bb babies
))
4654 (return (+ r
(* rr m
))) )) ))
4656 ;; Pollard rho for dlog computation (Brents variant of collision detection)
4658 (defun gf-dlog-rho-brent (a g p red
) ;; g is generator of order p
4659 #+ (or ccl ecl gcl
) (declare (optimize (speed 3) (safety 0)))
4661 ((equal '(0 1) a
) 0)
4663 ((equal a
(gf-sq g red
)) 2)
4664 ((equal '(0 1) (gf-times a g red
)) (1- p
))
4665 ((< p
32) (gf-dlog-naive a g red
))
4666 ((< p
1024) (gf-dlog-baby-giant a g p red
))
4668 (prog ((b (list 0 1)) (y 0) (z 0) ;; b = g^y * a^z
4669 (bb (list 0 1)) (yy 0) (zz 0) ;; bb = g^yy * a^zz
4672 (do ((i 0)(j 1)) (())
4673 (declare (fixnum i j
))
4674 (multiple-value-setq (b y z
) (gf-dlog-f b y z a g p red
))
4675 (when (equal b bb
) (return)) ;; g^y * a^z = g^yy * a^zz
4678 (setq j
(1+ (ash j
1)))
4679 (setq bb b yy y zz z
) ))
4680 (setq dy
(mod (- yy y
) p
) dz
(mod (- z zz
) p
)) ;; g^dy = a^dz = g^(x*dz)
4681 (when (= 1 (gcd dz p
))
4682 (return (zn-quo dy dz p
)) ) ;; x = dy/dz mod p (since g is generator of order p)
4686 yy
(1+ (random (1- p
)))
4687 zz
(1+ (random (1- p
)))
4688 bb
(gf-times (gf-pow g yy red
) (gf-pow a zz red
) red
) )
4691 ;; -----------------------------------------------------------------------------
4694 ;; nth root in Galois Fields ---------------------------------------------------
4697 (defmfun $ef_nth_root
(a r
)
4698 (ef-field?
"ef_nth_root")
4699 (unless (and (integerp r
) (> r
0))
4700 (gf-merror (intl:gettext
"Second argument to `ef_nth_root' must be a positive integer. Found ~m.") a r
) )
4701 (let* ((*ef-arith?
* t
)
4702 (rts (gf-nrt (gf-p2x a
) r
*ef-red
* *ef-ord
*)) )
4703 (gf-nrt-exit rts
) ))
4705 (defmfun $gf_nth_root
(a r
)
4706 (gf-field?
"gf_nth_root")
4707 (unless (and (integerp r
) (> r
0))
4708 (gf-merror (intl:gettext
"Second argument to `gf_nth_root' must be a positive integer. Found ~m.") a r
) )
4709 (let* ((*ef-arith?
*)
4710 (rts (gf-nrt (gf-p2x a
) r
*gf-red
* *gf-ord
*)) )
4711 (gf-nrt-exit rts
) ))
4713 (defun gf-nrt-exit (rts)
4715 (setq rts
(mapcar #'gf-n2x
(sort (mapcar #'gf-x2n rts
) #'<)))
4716 (cons '(mlist simp
) (mapcar #'gf-x2p rts
)) ))
4718 ;; e.g. r=i*i*j*k, then x^(1/r) = (((x^(1/i))^(1/i))^(1/j))^(1/k)
4719 (defun gf-nrt (x r red ord
)
4720 (setq x
(gf-nred x red
))
4724 ((or (= 1 r
) (primep r
)) (setq rts
(gf-amm x r red ord
)))
4726 (let* (($intfaclim
) (rs (get-factor-list r
)))
4727 (setq rs
(sort rs
#'< :key
#'car
))
4731 #'(lambda (pe) (apply #'(lambda (p e
) (make-list e
:initial-element p
)) pe
))
4733 (setq rts
(gf-amm x
(car rs
) red ord
))
4734 (dolist (r (cdr rs
))
4735 (setq rts
(apply #'nconc
(mapcar #'(lambda (y) (gf-amm y r red ord
)) rts
))) ))))
4738 ;; inspired by Bach,Shallit 7.3.2
4739 (defun gf-amm (x r red ord
) ;; r prime, red irreducible
4742 (let (k n e u s m re xr xu om g br bu ab alpha beta rt
)
4745 ((and (= 0 (setq m
(mod ord
2)))
4746 (/= 1 (gf-jacobi x red
(if *ef-arith?
* *gf-card
* *gf-char
*))) )
4747 (return-from gf-amm nil
) )
4748 ((= 1 m
) ;; q = 2^n : unique solution
4750 `(,(gf-pow x
(ash (+ (ash ord
1) 2) -
2) red
)) ))
4752 (setq rt
(gf-pow x
(ash (+ ord
2) -
2) red
))
4753 (return-from gf-amm
`(,rt
,(gf-minus rt
))) )
4755 (let* ((twox (gf-plus x x
))
4756 (y (gf-pow twox
(ash (- ord
4) -
3) red
))
4757 (i (gf-times twox
(gf-times y y red
) red
))
4758 (rt (gf-times x
(gf-times y
(gf-nplus i
`(0 ,(gf-cminus-b 1))) red
) red
)) )
4759 (return-from gf-amm
`(,rt
,(gf-minus rt
))) ))))
4760 (multiple-value-setq (s m
) (truncate ord r
))
4761 (when (and (= 0 m
) (not (equal '(0 1) (gf-pow x s red
))))
4762 (return-from gf-amm nil
))
4763 ;; r = 3, first 2 cases:
4766 ((= 1 (setq m
(mod ord
3))) ;; unique solution
4768 `(,(gf-pow x
(truncate (1+ (ash ord
1)) 3) red
)) ))
4769 ((= 2 m
) ;; unique solution
4771 `(,(gf-pow x
(truncate (1+ ord
) 3) red
)) ))))
4772 ;; compute u,e with ord = u*r^e and r,u coprime:
4775 (multiple-value-setq (u1 m
) (truncate u1 r
))
4776 (when (/= 0 m
) (return))
4777 (setq u u1 e
(1+ e
)) )
4780 (setq rt
(gf-pow x
(inv-mod r u
) red
)) ;; unique solution, see Bach,Shallit 7.3.1
4784 (do () ((not (equal '(0 1) (gf-pow n s red
)))) ;; n is no r-th power
4785 (setq n
(gf-n2x (1+ (gf-x2n n
)))) )
4786 (setq g
(gf-pow n u red
)
4788 om
(gf-pow g
(truncate re r
) red
) ) ;; r-th root of unity
4790 ((or (/= 3 r
) (= 0 (setq m
(mod ord
9))))
4791 (setq xr
(gf-pow x u red
)
4792 xu
(gf-pow x re red
)
4793 k
(*f-dlog xr g red re
`((,r
,e
))) ;; g^k = xr
4794 br
(gf-pow g
(truncate k r
) red
) ;; br^r = xr
4795 bu
(gf-pow xu
(inv-mod r u
) red
) ;; bu^r = xu
4796 ab
(cdr (zn-gcdex1 u re
))
4799 (if (< alpha
0) (incf alpha ord
) (incf beta ord
))
4800 (setq rt
(gf-times (gf-pow br alpha red
) (gf-pow bu beta red
) red
)) )
4801 ;; r = 3, remaining cases:
4803 (setq rt
(gf-pow x
(truncate (+ (ash ord
1) 3) 9) red
)) )
4805 (setq rt
(gf-pow x
(truncate (+ ord
3) 9) red
)) ))
4806 (do ((i 1 (1+ i
)) (j (list 0 1)) (res (list rt
)))
4808 (setq j
(gf-times j om red
))
4809 (push (gf-times rt j red
) res
) ))))))
4811 ;; -----------------------------------------------------------------------------
4814 ;; tables of small fields ------------------------------------------------------
4817 (defmfun $gf_add_table
()
4818 (gf-data?
"gf_add_table")
4819 (let ((*ef-arith?
*)) (gf-add-table *gf-card
*)) )
4821 (defmfun $ef_add_table
()
4822 (ef-data?
"ef_add_table")
4823 (let ((*ef-arith?
* t
)) (gf-add-table *ef-card
*)) )
4825 (defun gf-add-table (card)
4828 (gf-x2n (gf-plus (gf-n2x (1- i
)) (gf-n2x (1- j
)))) )
4832 (defmfun $gf_mult_table
(&optional all?
)
4833 (gf-data?
"gf_mult_table")
4834 (let ((*ef-arith?
*))
4835 (gf-mult-table *gf-red
* *gf-irred?
* *gf-card
* all?
) ))
4837 (defmfun $ef_mult_table
(&optional all?
)
4838 (ef-data?
"ef_mult_table")
4839 (let ((*ef-arith?
* t
))
4840 (gf-mult-table *ef-red
* *ef-irred?
* *ef-card
* all?
) ))
4842 (defun gf-mult-table (red irred? card all?
)
4845 ((or irred?
;; field
4846 (equal all?
'$all
) )
4849 (gf-x2n (gf-times (gf-n2x i
) (gf-n2x j
) red
)))
4853 (do ((i 1 (1+ i
)) x
)
4856 (when (gf-unit-p x red
) (push x units
)) )
4857 (dolist (x units
(cons '($matrix simp
) (nreverse res
)))
4860 (mapcar #'(lambda (y) (gf-x2n (gf-times x y red
))) units
) )
4863 (defmfun $gf_power_table
(&rest args
)
4864 (gf-data?
"gf_power_table")
4865 (let ((*ef-arith?
*) all? cols
)
4866 (multiple-value-setq (all? cols
)
4867 (apply #'gf-power-table-args
(cons "gf_power_table" args
)) )
4869 (setq cols
*gf-ord
*)
4870 (when all?
(incf cols
)) )
4871 (gf-power-table *gf-red
* *gf-irred?
* *gf-card
* cols all?
) ))
4873 (defmfun $ef_power_table
(&rest args
)
4874 (ef-data?
"ef_power_table")
4875 (let ((*ef-arith?
* t
) all? cols
)
4876 (multiple-value-setq (all? cols
)
4877 (apply #'gf-power-table-args
(cons "ef_power_table" args
)) )
4879 (setq cols
*ef-ord
*)
4880 (when all?
(incf cols
)) )
4881 (gf-power-table *ef-red
* *ef-irred?
* *ef-card
* cols all?
) ))
4883 (defun gf-power-table-args (&rest args
)
4884 (let ((str (car args
)) all? cols
(x (cadr args
)) (y (caddr args
)))
4887 ((integerp x
) (setq cols x
))
4888 ((equal x
'$all
) (setq all? t
))
4889 (t (gf-merror (intl:gettext
4890 "First argument to `~m' must be `all' or a small fixnum." ) str
))))
4893 ((and (integerp x
) (equal y
'$all
)) (setq all? t
))
4894 ((and (equal x
'$all
) (integerp y
)) (setq cols y
))
4895 (t (format t
"Only the first argument to `~a' has been used.~%" str
) )))
4896 (values all? cols
) ))
4898 (defun gf-power-table (red irred? card cols all?
)
4902 #'(lambda (i j
) (gf-x2n (gf-pow (gf-n2x i
) j red
)))
4906 (do ((i 1 (1+ i
)) x res
)
4907 ((= i card
) (cons '($matrix simp
) (nreverse res
)))
4909 (when (gf-unit-p x red
)
4912 (mapcar #'(lambda (j) (gf-x2n (gf-pow x j red
)))
4913 (cdr (mfuncall '$makelist
'$j
'$j
1 cols
)) ))
4916 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;