source: CGBLisp/src/ratpoly.lisp@ 1

Last change on this file since 1 was 1, checked in by Marek Rychlik, 15 years ago

First import of a version circa 1997.

File size: 9.7 KB
Line 
1#|
2 $Id: ratpoly.lisp,v 1.4 2009/01/22 04:07:33 marek Exp $
3 *--------------------------------------------------------------------------*
4 | Copyright (C) 1994, Marek Rychlik (e-mail: rychlik@math.arizona.edu) |
5 | Department of Mathematics, University of Arizona, Tucson, AZ 85721 |
6 | |
7 | Everyone is permitted to copy, distribute and modify the code in this |
8 | directory, as long as this copyright note is preserved verbatim. |
9 *--------------------------------------------------------------------------*
10|#
11;; Operations in the ring k(x2,x3,...,xn)[x1]
12;; The representation is (n1 a1 n2 a2 ... nk ak)
13;; where ak are rational functions in an arbitrary number of variables
14;; as in the "rat" package; this representation is referred to as RATPOLY
15;;
16;; Another representation is POLY1 and this corresponds to reppresenting
17;; polynomials as elements of k[x2,x3,...,xn][x1]
18;;
19;; In order to facilitate input, a function called
20;; poly-to-ratpoly is provided; it converts a polynomial in alist form
21;; to a form like above (plist form) with ai being rational
22;; Output is done by function ratpoly-print
23;;
24
25(defpackage "RATPOLY"
26 (:export ratpoly+ ratpoly- ratpoly* ratpoly-uminus scalar-times-ratpoly
27 rat-times-ratpoly ratpoly-divide ratpoly-remainder
28 ratpoly-gcd ratpoly-diff ratpoly-square-free
29 ratpoly-normalize ratpoly-resultant
30 deg lead ratpoly-discriminant ratpoly-print
31 poly-to-ratpoly ratpoly-to-poly poly-resultant)
32 (:use "RAT" "PRINTER" "MONOM" "DIVISION" "TERM" "POLY" "COMMON-LISP"))
33
34(in-package "RATPOLY")
35
36#+debug(proclaim '(optimize (speed 0) (debug 3)))
37#-debug(proclaim '(optimize (speed 3) (safety 0)))
38
39;; Arithmetic on polynomials in one variable
40;; The polynomial a1 * x^n1 + a2 * x^n2 + ... + ak * x^nk
41;; where ai are nonzero numbers and n1>n2>...>nk is represented as list
42;; (n1 a1 n2 a2 ... nk ak)
43;; This is the sparse recursive representation
44
45(defun ratpoly+ (p q)
46 "Add polynomials P and Q."
47 (cond ((endp p) q)
48 ((endp q) p)
49 ((= (car p) (car q))
50 (let ((s (rat+ (cadr p) (cadr q))))
51 (if (rat-zerop s) ;check for cancellation
52 (ratpoly+ (cddr p) (cddr q))
53 (append (list (car p) s)
54 (ratpoly+ (cddr p) (cddr q))))))
55 ((> (car p) (car q))
56 (append (list (car p) (cadr p))
57 (ratpoly+ (cddr p) q)))
58 (t (append (list (car q) (cadr q))
59 (ratpoly+ p (cddr q))))))
60
61(defun ratpoly- (p q)
62 ;;"Subtract polynomial Q from P."
63 (cond ((endp p) (ratpoly-uminus q))
64 ((endp q) p)
65 ((= (car p) (car q))
66 (let ((s (rat- (cadr p) (cadr q))))
67 (if (rat-zerop s) ;check for cancellation
68 (ratpoly- (cddr p) (cddr q))
69 (append (list (car p) s)
70 (ratpoly- (cddr p) (cddr q))))))
71 ((> (car p) (car q))
72 (append (list (car p) (cadr p))
73 (ratpoly- (cddr p) q)))
74 (t (append (list (car q) (rat-uminus (cadr q)))
75 (ratpoly- p (cddr q))))))
76
77(defun ratpoly-uminus (p)
78 (cond
79 ((endp p) nil)
80 (t (cons (car p) (cons (rat-uminus (cadr p)) (ratpoly-uminus (cddr p)))))))
81
82(defun ratpoly* (p q)
83 "Multiply polynomials P and Q."
84 (cond ((or (endp p) (endp q)) nil) ;p or q is 0 (represented by NIL)
85 ;; If p=p0+p1 and q=q0+q1 then pq=p0q0+p0q1+p1q
86 (t (append (list (+ (car p) (car q)) (rat* (cadr p) (cadr q)))
87 (ratpoly+ (ratpoly* (list (car p) (cadr p)) (cddr q))
88 (ratpoly* (cddr p) q))))))
89
90(defun scalar-times-ratpoly (scalar p)
91 "Multiply scalar SCALAR by a polynomial P."
92 (cond ((endp p) nil)
93 (t (cons (car p)
94 (cons (scalar-times-rat scalar (cadr p))
95 (scalar-times-ratpoly scalar (cddr p)))))))
96
97(defun rat-times-ratpoly (scalar p)
98 "Multiply rational function SCALAR by a polynomial P."
99 (cond ((endp p) nil)
100 (t (cons (car p)
101 (cons (rat* scalar (cadr p))
102 (rat-times-ratpoly scalar (cddr p)))))))
103
104(defun ratpoly-divide (f g)
105 "Divide polynomial F by G. Return quotient and remainder as multiple values."
106 (do* ((lp nil (- (car r) (car g)))
107 (lc nil (rat/ (cadr r) (cadr g)))
108 (q nil (nconc q (list lp lc)))
109 (r f (ratpoly- (cddr r) (ratpoly* (list lp lc) (cddr g)))))
110 ((or (endp r) (< (car r) (car g)))
111 (values q r))))
112
113(defun ratpoly-remainder (f g)
114 "The remainder of the division of a polynomial F by G."
115 (second (multiple-value-list (ratpoly-divide f g))))
116
117(defun ratpoly-gcd (f g)
118 "Return GCD of polynomials F and G."
119 (do ((h f s)
120 (s g (ratpoly-remainder h s)))
121 ((endp s) h)))
122
123(defun ratpoly-diff (f)
124 "Differentiate a polynomial."
125 (cond ((endp f) nil)
126 ((zerop (car f)) nil) ;degree 0
127 (t (append (list (1- (car f)) (scalar-times-rat (car f) (cadr f)))
128 (ratpoly-diff (cddr f))))))
129
130(defun ratpoly-square-free (f)
131 "Return the square-free part of a polynomial F."
132 (ratpoly-divide f (ratpoly-gcd f (ratpoly-diff f))))
133
134(defun ratpoly-normalize (f)
135 "Divide a non-zero polynomial by the coefficient at the highest power."
136 (rat-times-ratpoly (cons (denom (cadr f)) (num (cadr f))) f))
137
138;; A modification of Euclidean algorithm
139(defun ratpoly-resultant (f g)
140 "Return the resultant of polynomials F and G."
141 (do* ((r nil (ratpoly-remainder h s))
142 (res (list 0 (rat-constant 1 (length (car (caaadr f)))))
143 (rat-times-ratpoly
144 (scalar-times-rat
145 (expt -1 (* (deg h) (deg s)))
146 (rat-expt (lead s) (- (deg h) (deg r))))
147 res))
148 (h f s)
149 (s g r))
150 ((<= (deg s) 0)
151 (cond
152 ((or (endp s) (endp h)) nil)
153 ((plusp (deg h))
154 (rat-times-ratpoly (rat-expt (lead s) (deg h))
155 res))))))
156
157(defun deg (s)
158 (cond
159 ((endp s)
160 #+debugging(warn "ratpoly::deg: Calculating degree of 0 polynomial")
161 -1)
162 (t (car s))))
163
164(defun lead (s) (cadr s))
165
166(defun ratpoly-discriminant (p &aux (l (deg p)))
167 "The discriminant of a polynomial P."
168 (rat-times-ratpoly
169 (scalar-div-rat (expt -1 (mod (* l (1- l)) 2)) (lead p))
170 (ratpoly-resultant p (ratpoly-diff p))))
171
172(defun ratpoly-print (p vars &optional (stream t) (beg t) (p-orig p))
173 (when (endp p)
174 (when beg (format stream "0"))
175 (return-from ratpoly-print p-orig))
176 (if beg (format stream "((")
177 (format stream " + (("))
178 (poly-print (caadr p) (rest vars) stream)
179 (format stream ") / (")
180 (poly-print (cdadr p) (rest vars) stream)
181 (case (car p)
182 (1 (format stream ")) * ~a" (car vars)))
183 (0 (format stream "))" (car vars)))
184 (otherwise
185 (format stream ")) * ~a^~d" (car vars) (car p))))
186 (ratpoly-print (cddr p) vars stream nil p-orig))
187
188(defun poly-to-ratpoly (p)
189 (poly1-to-ratpoly (poly-to-poly1 p)))
190
191;; Convert a polynomial to a polynomial in k[x2,...,xn][x1]
192(defun poly-to-poly1 (p &aux (htab (make-hash-table)) q)
193 (dolist (term p)
194 (push (cons (cdar term) (cdr term))
195 (gethash (caar term) htab nil)))
196 (maphash #'(lambda (key val) (push (cons key val) q)) htab)
197 (mapcan #'(lambda (x &aux (deg (car x)) (coef (cdr x)))
198 (list deg
199 (sort-poly coef)))
200 (sort q #'> :key #'car)))
201
202
203;; Convert poly1 to ratpoly, i.e. add denominators=1
204(defun poly1-to-ratpoly (p)
205 (unless (endp p)
206 (cons (car p)
207 (cons
208 (cons (cadr p)
209 (list
210 (cons (make-list (length (caaadr p)) :initial-element 0) 1)))
211 (poly1-to-ratpoly (cddr p))))))
212
213(defun ratpoly-to-poly1 (p)
214 "Convert every coefficient of ratpoly to polynomial if possible"
215 (cond
216 ((endp p) nil)
217 (t (cons (car p)
218 (cons (rat-to-poly (cadr p))
219 (ratpoly-to-poly1 (cddr p)))))))
220
221(defun poly1-to-poly (p)
222 "Convert a ratpoly, whose coeffs have been converted to poly,
223into a poly structure, i.e. tack in powers of first variable."
224 (cond
225 ((endp p) nil)
226 (t
227 (append
228 (mapcar #'(lambda (x) (cons (cons (car p) (car x)) (cdr x))) (cadr p))
229 (poly1-to-poly (cddr p))))))
230
231(defun ratpoly-to-poly (p)
232 (poly1-to-poly (ratpoly-to-poly1 p)))
233
234
235(defun poly-resultant (f g)
236 "Calculate resultant of F and G given in poly i.e. alist representation."
237 (ratpoly-to-poly
238 (ratpoly-resultant (poly-to-ratpoly f)
239 (poly-to-ratpoly g))))
240
241#|
242;;----------------------------------------------------------------
243;; Multi-variable GCD algorithm
244;; Roughly p. 134 of Davenport, Siret, Tournier
245;;----------------------------------------------------------------
246(defun poly-gcd (A B)
247 (multiple-value-bind (Ap Ac)
248 (primitive-part (poly-to-poly1 A))
249 (multiple-value-bind (Bp Bc)
250 (primitive-part (poly-to-poly1 B))
251 (poly* (poly1-to-poly (primitive-part (euclid Ap Bp)))
252 (poly1-to-poly
253 (list 0
254 (cond
255 ((numberp Ac) (list (cons nil (gcd Ac Bc))))
256 (t (poly-gcd Ac Bc)))))))))
257
258;; This operates on poly1
259(defun content1 (A)
260 (cond
261 ((endp A) (error "content1: Content of 0 is not defined."))
262 ((endp (caaadr A)) ;1-variable poly
263 (content1-aux A)) ;a number
264 ((endp (cddr A)) (cadr A))
265 (t (poly-gcd (cadr A) (content1 (cddr A))))))
266
267;; 1-variable case
268(defun content1-aux (A)
269 (cond ((endp A) (error "content1-aux: Content of 0 is not defined."))
270 ((endp (cddr A)) (cdaadr A))
271 (t (gcd (cdaadr A) (content1-aux (cddr A))))))
272
273;; operates on poly
274(defun content (A &aux (A1 (poly-to-poly1 A)))
275 (content1 A1))
276
277;; Operates on poly1
278(defun primitive-part (A)
279 (let ((Ac (content1 A)))
280 (values (divide-coeffs A Ac) Ac)))
281
282;; Operates on A in poly1 form and A in poly form of 1 variable less
283(defun divide-coeffs (A Ac)
284 (cond
285 ((endp A) nil)
286 ((numberp Ac) ;ground case
287 (cons (car A)
288 (cons (list (cons nil (floor (cdaadr A) Ac)))
289 (divide-coeffs (cddr A) Ac))))
290 (t (cons (car A)
291 (cons
292 (multiple-value-bind (q r)
293 (divide (cadr A) (list Ac))
294 (unless (endp r) (error "divide-coeffs: not divisible."))
295 (car q))
296 (divide-coeffs (cddr A) Ac))))))
297
298;; Euclid operates on poly1
299(defun euclid (A B)
300 (ratpoly-to-poly1 (ratpoly-gcd (poly1-to-ratpoly A)
301 (poly1-to-ratpoly B))))
302
303|#
304
Note: See TracBrowser for help on using the repository browser.