home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
language
/
examples
/
lll.lsp
< prev
next >
Wrap
Lisp/Scheme
|
1993-10-23
|
7KB
|
137 lines
;; 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))))
|#