home *** CD-ROM | disk | FTP | other *** search
- ;; Lovász' Gitterbasis-Reduktions-Algorithmus
-
- ;; Bruno Haible 15.8.1989
- ;; Nach
- ;; A. K. Lenstra, H. W. Lenstra, L. Lovász: Factoring polynomials with
- ;; rational coefficients. Math. Ann. 261 (1982), 515-534.
- ;; und
- ;; Erich Kaltofen: Polynomial factorization 1982-1986, preprint.
-
- (provide 'LLL)
-
- ; Input: basis = Sequence von n linear unabhängigen Vektoren im Z^m
- ; Output: reduzierte Gitterbasis als Sequence von Vektoren im Z^m
- (defun LLL (basis)
- (let ((n (length basis)))
- (when (or (= n 0) (= n 1)) (return-from LLL basis))
- (let ((m (length (elt basis 0))))
- (labels ((scalprod (b1 b2) ; Skalarprodukt zweier Vektoren
- (let ((sum 0))
- (dotimes (i m) (incf sum (* (aref b1 i) (aref b2 i))))
- sum
- ) )
- (norm2 (b) ; Normquadrat eines Vektors
- (scalprod b b)
- ))
- ; Gram-Schmidt-Initialisierung:
- (let ((b (map 'vector #'copy-seq basis))
- (beta (make-array n))
- (mu (make-array `(,n ,n))))
- (do ((i 0 (1+ i))) ((= i n))
- (do ((j 0 (1+ j))) ((= j i))
- (setf (aref mu i j)
- (/ (- (scalprod (aref b i) (aref b j))
- (let ((sum 0))
- (do ((l 0 (1+ l))) ((= l j) sum)
- (incf sum (* (aref mu j l) (aref mu i l) (aref beta l)))
- ) ) )
- (aref beta j)
- ) ) )
- (setf (aref beta i)
- (- (norm2 (aref b i))
- (let ((sum 0))
- (do ((l 0 (1+ l))) ((= l i) sum)
- (incf sum (* (expt (aref mu i l) 2) (aref beta l)))
- ) ) ) )
- )
- ; Hier repräsentieren beta und mu die Koeffizienten der
- ; Gram-Schmidt-Orthogonalisierung von b:
- ; Für 0<=i<n ist b*[i] = b[i] - sum(j=0..i-1, mu[i,j] b*[j])
- ; mit mu[i,j] = b[i] b*[j] / beta[j]
- ; und beta[j] = b*[j] b*[j].
- (do ((k 1)) (nil)
- ; Hier ist das Teilstück b[0],...,b[k-1] der Basis reduziert,
- ; d.h. für 0<=j<i<=k-1 ist |mu[i,j]|<=1/2 und
- ; für 0<l<=k-1 ist beta[l] >= beta[l-1]/2.
- (if (or (= k 0) (>= (* 2 (aref beta k)) (aref beta (1- k))))
- (progn
- ; Für 0<l<=k ist beta[l] >= beta[l-1]/2.
- (incf k) ; k erhöhen
- ; Für 0<l<k ist beta[l] >= beta[l-1]/2.
- (when (= k n) (return-from LLL b))
- ; Ersetze b[k] durch b[k]-r*b[l] für verschiedene
- ; r zu jedem l=0..k-1. Dabei bleiben alle b*[j] erhalten.
- (do ((l (1- k) (1- l))) ((< l 0))
- (let ((r (round (aref mu k l))))
- (unless (zerop r) ; bei r=0 verändert sich nichts
- ; (setf (aref b k) (- (aref b k) (* r (aref b l)))) ==
- (dotimes (j m)
- (decf (aref (aref b k) j) (* r (aref (aref b l) j)))
- )
- ; mu[k,.] adjustieren: Da jetzt gilt
- ; b*[k] = (b[k]+rb[l]) - sum(j=0..k-1, mu[k,j] b*[j])
- ; = b[k] - sum(j=0..k-1, mu[k,j] b*[j])
- ; + r b*[l] + r sum(j=0..l-1, mu[l,j] b*[j])
- ; muß mu[k,j] um r*mu[l,j] (für j<l) bzw. um r (für j=l)
- ; erniedrigt werden:
- (do ((j 0 (1+ j))) ((= j l))
- (decf (aref mu k j) (* r (aref mu l j)))
- )
- (decf (aref mu k l) r) ; dadurch wird |mu[k,l]|<=1/2
- ) ) ) )
- ; Vertausche b[k-1] und b[k]. Dabei sind auch beta[k-1] und
- ; beta[k] zu vertauschen und mu[k-1,.], mu[k,.], mu[.,k-1],
- ; mu[.,k] zu adjustieren.
- (let* ((k-1 (1- k))
- (mu_k_k-1 (aref mu k k-1))
- (gamma_k-1 (+ (aref beta k) (* (expt mu_k_k-1 2) (aref beta k-1))))
- (h (/ (aref beta k) gamma_k-1))
- (nu_k_k-1 (/ (* mu_k_k-1 (aref beta k-1)) gamma_k-1)))
- (do ((j 0 (1+ j))) ((= j k-1))
- (rotatef (aref mu k-1 j) (aref mu k j))
- )
- (do ((i (1+ k) (1+ i))) ((= i n))
- (psetf (aref mu i k-1) (+ (* (aref mu i k-1) nu_k_k-1) (* (aref mu i k) h))
- (aref mu i k) (- (aref mu i k-1) (* (aref mu i k) mu_k_k-1))
- ) )
- (setf (aref beta k) (* (aref beta k-1) h))
- (setf (aref beta k-1) gamma_k-1)
- (setf (aref mu k k-1) nu_k_k-1)
- (rotatef (aref b k-1) (aref b k))
- (setq k k-1) ; Nun muß k verkleinert werden
- )
- ) )
- ) ) ) ) )
-
- #|
- ; Bestimmt das Minimalpolynom (über Z) einer komplexen algebraischen Zahl x.
- ; Sie ist gegeben durch eine Funktion, die - mit einer ganzen Zahl k>=0 als
- ; Argument aufgerufen - eine komplexe Zahl liefert, die sich von 2^k*x sowohl
- ; im Realteil als auch im Imaginärteil um höchstens 1/2 unterscheidet.
- ; Dazu muß noch eine Gradabschätzung nach oben m und die L2-Norm |f| eines
- ; x annullierenden Polynoms f/=0 angegeben werden.
- ; Ergebnis ist das Minimalpolynom von x in der Form #(g0 ... gk)
- ; für g(x) = g0*x^0+...+gk*x^k == 0.
- (defun minpoly (fun m |f|)
- (let* ((B0 (float |f| 0d0))
- (B1 (* (float (/ (! (* 2 m)) (expt (! m) 2)) 0d0) B0))
- (B2 (* (sqrt (+ m 2.0d0)) B1))
- (B3 (* (sqrt (float (expt 2 m) 0d0)) B2))
- (B4 (expt (* B1 B3) m))
- (x0 (funcall fun 0)) ; grobe Näherung für x
- (Betragsschranke ; Abschätzung für |x| nach oben, >=1
- (max (sqrt (+ (expt (+ (abs (realpart x0)) 0.5d0) 2)
- (expt (+ (abs (imagpart x0)) 0.5d0) 2)
- ) )
- 1.0d0
- ) )
- (B5 (* m (expt Betragsschranke (1- m)) B4))
- (B6 (* (sqrt (+ m 3.0d0)) B3 B5))
- (k (nth-value 1 (decode-float B6)) ; 2^k>B6
- ; Brauche 2^k*x,...,2^k*x^m auf Genauigkeit 1/2.
- (MM (* m (expt (+ Betragsschranke 0.25d0) (1- m)) (expt 2 (+ k 2))))
- ; Brauche x auf Genauigkeit 1/MM.
- (x (funcall fun (nth-value 1 (decode-float MM))))
- |#
-
-