Fix typo
[maxima.git] / share / affine / aquotient.lisp
blob2363f1b3d2c60788d4bf1914e23beef886dda4c2
1 ;;; -*- Package: MAXIMA; Base: 10.; Syntax: Common-lisp -*-
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; ;;;;;
4 ;;; Copyright (c) 1984 by William Schelter,University of Texas ;;;;;
5 ;;; All rights reserved ;;;;;
6 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 (in-package :maxima)
10 (eval-when
11 (:compile-toplevel :load-toplevel :execute)
13 (defmacro p-cof (f) ;leading coefficient of f
14 `(third ,f))
16 (defmacro p-next-term (f)
17 `(cddr ,f))
19 (defmacro p-deg (f)
20 `(second ,f))
22 (defmacro term-cof (terms)
23 `(second ,terms))
25 (defmacro term-deg (terms)
26 `(first ,terms)))
28 ;;(make-poly var x)==> (list x 1 1)
30 (defun make-polynomial (&key var terms)
31 (psimp var terms))
33 (defun afc-quotient (f g)
34 (cquotient f g))
36 (defun fsignal (&rest l)
37 (error (car l)))
39 (defmacro working-modulo (list-of-monic-polynomials &body body &aux (old-tellrats (make-symbol "old-tellrats")))
40 "The computations in body are done modulo the list-of-monic-polynomials. The
41 results of squareing,multiplication, and exponentiating should be of lower degree in each of the
42 monic polynomials than the degree of the monic polynomial"
43 `(let ((,old-tellrats (list-previous-tellrats ,list-of-monic-polynomials)))
44 (unwind-protect
45 (progn
46 (set-tellrats ,list-of-monic-polynomials)
47 ,@body)
48 (undo-tellrats ,old-tellrats))))
50 ;;sample usage
51 ;;(working-modulo (st-rat #$[x^2+x+1,y^4+y]$) (ptimes ...))
53 (defun list-previous-tellrats (new-tellrats)
54 (loop for v in new-tellrats
55 collecting (cons (car v) (get (car v) 'tellrat))))
57 (defun set-tellrats (new-tellrats)
58 (loop for v in new-tellrats
59 do (putprop (car v) (cdr v) 'tellrat)))
61 (defun undo-tellrats (old-list)
62 (loop for v in old-list
63 when (null (cdr v))
64 do (remprop (car v) 'tellrat)
65 else do (putprop (car v) (cdr v) 'tellrat)))
67 ;;version for possibly some zero terms resulting
68 ;;using nconc less space but slower since (list a b) is cdr coded and it has to fix up.
69 (defmacro term-operation (f g operation-function &optional deg-shift-result)
70 "If f and g are polynomials this constructs polynomial whose main variable is the same as f ~
71 with coefficients (operation-function f_i g)..[f_i means the i'th coefficient of f
72 degree (+ i deg-shift-result)"
73 (let ((cof (make-symbol "cof"))
74 (deg (make-symbol "deg"))
75 (tem (gensym)))
76 `(psimp (p-var ,f)
77 (loop for (,deg ,cof) on (cdr ,f) by #'cddr
78 with ,tem
79 do (setq ,tem (,operation-function ,cof ,g))
80 when (not (pzerop ,tem))
81 nconc (list , (cond (deg-shift-result `(+ ,deg ,deg-shift-result))
82 (t deg))
83 ,tem)))))
85 (defmacro plain-term-operation (terms-f terms-g operation-function &optional deg-shift-result)
86 "constructs terms of a polynomial with coefficients (operation-function f_i terms-g) in
87 degree (+ i deg-shift-result)"
88 (let ((cof (make-symbol "cof"))
89 (deg (make-symbol "deg"))
90 (tem (gensym)))
91 `(loop for (,deg ,cof) on ,terms-f by #'cddr
92 with ,tem
93 do (setq ,tem (,operation-function ,cof ,terms-g))
94 when (not (pzerop ,tem))
95 nconc (list ,(cond (deg-shift-result `(+ ,deg ,deg-shift-result))
96 (t deg))
97 ,tem))))
99 (defmacro quotient-not-exact ()
100 `(cond ((and (boundp '*testing*)
101 *testing*)
102 (throw 'quotient-not-exact t))
103 (t (fsignal 'quotient-not-exact))))
106 (DEFUN afp-CQUOTIENT (A B)
107 (declare (special *testing*))
108 (COND ((EQl A 0) 0)
109 ((NULL MODULUS)
110 (let ((quot (quotient a b)))
111 (cond ((eql (* quot b) a)
112 quot)
113 (t (quotient-not-exact)))))
114 (t (ctimes a (crecip b)))))
117 ;;The following works to eliminate zero terms when using modulus etc.
118 ;;It is also faster than ptimes by a slight margin.
119 ;;unlike ptimes which may introduce zero terms eg:
120 ;;(let ((modulus 4))(ptimes (x+y+z)^4 (x+y+z)^4) gives a bad result
124 (defun afp-terms-times (terms-f terms-g &aux answ (g-orig terms-g) prod-exp tail prod-cof)
125 "Returns the terms of the polynomial which is the product of the two polynomials ~
126 whose terms are terms-f and terms-g. If modulus is in effect the the result will have its ~
127 coefficients reduced by modulus."
128 (cond
129 (terms-g (setq answ (plain-term-operation terms-g (term-cof terms-f) afp-times (term-deg terms-f)))
130 (loop for (f-exp f-cof ) on (cddr terms-f) by #'cddr
132 (setq terms-g g-orig)
133 (prog ()
134 first-product
135 (cond ((null terms-g)(return nil)))
136 (setq prod-exp (+ f-exp (term-deg terms-g)))
137 (setq prod-cof (afp-times(term-cof terms-g) f-cof))
138 (cond ((pzerop prod-cof) (setq terms-g (cddr terms-g)) (go first-product))
139 ((or (null answ) (> prod-exp (term-deg answ)))
140 (setq answ (cons prod-exp (cons prod-cof answ)))
141 (setq tail (cdr answ)) (go next-product))
142 ((eql prod-exp (term-deg answ))
143 (setq prod-cof (pplus (term-cof answ) prod-cof))
144 (cond ((pzerop prod-cof) (setq answ (cddr answ))
145 (setq terms-g (cddr terms-g)) (go first-product))
146 (t (setf (term-cof answ) prod-cof)
147 (setq tail (cdr answ)) (go next-product)))))
148 ;;below here assume answ not empty and (term-deg answ)
149 ;;greater any possible future prod-exp (until next
150 ;;f-exp,f-cof) Once below this point we stay below,
151 ;;until next f-exp,f-cof . Tail begins with the
152 ;;coefficient whose corresponding degree is definitely
153 ;;higher than any prod-exp to be encountered.
154 (setq tail (cdr answ))
155 tail-certain
156 (cond ((and (cdr tail)(> (second tail) prod-exp))
157 (setq tail (cddr tail)) (go tail-certain)))
158 (cond ((or (null (cdr tail))(< (second tail) prod-exp))
159 (setf (cdr tail) (cons prod-exp (cons prod-cof (cdr tail))))
160 (setq tail (cddr tail)) (go next-product)))
161 (cond ((pzerop (setq prod-cof (pplus (third tail) prod-cof)))
162 (setf (cdr tail) (cdddr tail)))
163 (t (setf (third tail) prod-cof) (setq tail (cddr tail))))
164 next-product
165 (setq terms-g (cddr terms-g))
166 (cond ((null terms-g) (return nil)))
167 (setq prod-exp (+ f-exp (car terms-g)))
168 (setq prod-cof (afp-times (second terms-g) f-cof))
169 (cond ((pzerop prod-cof) (go next-product)))
170 (go tail-certain)))))
171 answ)
173 (defmacro afp-main-plus-non-main (constant f-main)
174 "Adds a polynomial CONSTANT to a polynomial whose main variable is higher than
175 any in F-MAIN"
176 `(psimp (p-var ,f-main) (afp-constant-term-plus ,constant (cdr ,f-main))))
178 (defmacro afp-number-plus (number poly)
179 "Adds a NUMBER to a polynomial POLY, returning the result"
180 `(cond ((numberp ,poly)(cplus ,number ,poly))
181 (t (afp-main-plus-non-main ,number ,poly))))
183 (defun afp-plus (f g)
184 "Returns the sum of the two polynomials f and g"
185 (cond ((numberp f) (afp-number-plus f g))
186 ((numberp g) (afp-number-plus g f))
187 ((eq (p-var f) (p-var g))
188 (psimp (p-var f)
189 (afp-terms-plus (cdr f) (cdr g))))
190 ((pointergp (p-var f) (p-var g)) (afp-main-plus-non-main g f))
191 (t (afp-main-plus-non-main f g))))
193 (defun afp-constant-term-plus (constant terms)
194 "Adds a polynomial (CONSTANT) not involving the main variable of a polynomial whose
195 terms are TERMS. Naturally the main variable is assumed higher than any in the CONSTANT. ~
196 The result is the terms of the sum polynomial"
197 (cond ((pzerop constant) terms)
198 ((null terms)
199 (list 0 constant))
200 ((zerop (car terms))(setq constant (afp-plus constant (second terms)))
201 (cond ((pzerop constant)nil)
202 (t (list 0 constant))))
203 (t (cons (car terms) (cons (second terms) (afp-constant-term-plus constant (cddr terms)))))))
206 (defun afp-terms-plus (terms-f terms-g &aux e)
207 "Returns the terms of the polynomial which is the sum of f and g
208 if the terms of f and the terms of g are the two arguments."
209 (cond ((null terms-f) terms-g)
210 ((null terms-g) terms-f)
211 ((eql (car terms-f) (car terms-g))
212 (setq e (afp-plus (second terms-f) (second terms-g)))
213 (cond ((pzerop e)(afp-terms-plus (cddr terms-f) (cddr terms-g)))
214 (t (cons (car terms-f) (cons e (afp-terms-plus (cddr terms-f) (cddr terms-g)))))))
215 ((> (car terms-f) (car terms-g ))(cons (car terms-f) (cons (second terms-f)
216 (afp-terms-plus terms-g (cddr terms-f)))))
217 (t(cons (car terms-g) (cons (second terms-g)
218 (afp-terms-plus terms-f (cddr terms-g)))))))
221 (defmacro qfirstn (n l)
222 (case n
223 (1 `(list (car ,l)))
224 (2 `(list (car ,l) (second ,l)))
225 (t `(subseq ,l 0 ,n))))
227 (defun afp-minus (f)
228 "makes no check that keeping in the modulus range nor that the result is reduced,
229 but the result g will satisfy (afp-plus f g) ==> 0"
230 (cond ((numberp f) (cminus f))
231 (t (cons (car f) (afp-terms-minus (cdr f))))))
233 (defun afp-terms-minus (terms-f)
234 (loop for (deg pol) on terms-f by #'cddr nconc (list deg (afp-minus pol))))
236 (defmacro add-one-term (deg cof terms)
237 (cond ((symbolp cof)
238 `(cond ((pzerop ,cof) ,terms)
239 (t (cons ,deg (cons ,cof ,terms)))))
241 `(let ((.cof. ,cof))
242 (cond ((pzerop .cof.) ,terms)
243 (t (cons ,deg (cons .cof. ,terms))))))))
245 (defun afp-difference (f g)
246 (cond ((numberp f)
247 (cond ((numberp g)(cdifference f g))
248 (t (psimp (p-var g) (afp-terms-constant-main-differ f (cdr g))))))
249 ((numberp g)
250 (psimp (p-var f) (afp-terms-main-constant-differ (cdr f) g)))
251 ((eq (p-var f) (p-var g))
252 (psimp (p-var f) (afp-terms-differ (p-terms f) (p-terms g))))
253 ((pointergp (p-var f) (p-var g))
254 (psimp (p-var f) (afp-terms-main-constant-differ
255 (cdr f) g)))
256 (t(psimp (p-var g) (afp-terms-main-constant-differ
257 f (cdr g))))))
261 (defun afp-terms-differ (terms-f terms-g)
262 (cond ((null terms-f) (afp-terms-minus terms-g))
263 ((null terms-g) terms-f)
264 ((eql (term-deg terms-f) (term-deg terms-g))
265 (add-one-term (term-deg terms-f) (afp-difference (term-cof terms-f) (term-cof terms-g))
266 (afp-terms-differ (cddr terms-f) (cddr terms-g))))
267 ((> (term-deg terms-f) (term-deg terms-g))
268 (cons (term-deg terms-f) (cons (term-cof terms-f) (afp-terms-differ (p-next-term terms-f) terms-g))))
270 (cons (term-deg terms-g) (cons (afp-minus (term-cof terms-g)) (afp-terms-differ terms-f (p-next-term terms-g)))))))
272 (defun afp-terms-constant-main-differ (const main)
273 "main is terms const is a polynomial"
274 (cond ((null main)(cond ((pzerop const) nil)
275 (t (list 0 const))))
276 ((zerop (car main))
277 (add-one-term 0 (afp-difference (second main) const) nil))
278 (t (cons (car main) (cons (afp-minus (second main)) (afp-terms-constant-main-differ const (cddr main)))))))
280 (defun afp-terms-main-constant-differ (main const)
281 (cond ((null main)(cond ((pzerop const) nil)
282 (t (list 0 (afp-minus const)))))
283 ((zerop (car main))
284 (add-one-term 0 (afp-difference (second main) const) nil))
285 (t (cons (car main) (cons (second main) (afp-terms-main-constant-differ (cddr main) const))))))
287 ;;assumes divides evenly, integer coefficients.
288 ;;signal error otherwise the flavor of the error should be specified.
289 (defun afp-quotient (f g)
290 "Tries to divide the polynomial f by g. One has result*g=f, or else ~
291 it signals an error."
292 (declare (special *testing*))
293 (cond ((numberp f)
294 (cond ((numberp g)
295 (afp-cquotient f g))
296 ((zerop f) 0)
297 (t (quotient-not-exact))))
298 ((numberp g)
299 (term-operation f g afp-quotient))
300 ((pointergp (p-var f) (p-var g))
301 (term-operation f g afp-quotient))
302 ((eq (p-var f) (p-var g))
303 (loop
304 with quot with deg-dif with main-var = (p-var f) with minus-quot
306 (setq deg-dif (- (p-deg f) (p-deg g)))
307 while (>= deg-dif 0)
308 collecting deg-dif into q
309 collecting (setq quot (afp-quotient (p-cof f) (p-cof g)))
310 into q
311 do (setq minus-quot (pminus quot))
312 (setq f (pplus
314 (term-operation g
315 ;;-fn/gm
316 minus-quot
317 ptimes
318 deg-dif)))
319 while (not (and (numberp f) (zerop f)))
320 when (or (numberp f) (not (eq main-var (p-var f)))
321 (< (p-deg f) (p-deg g)))
322 do (quotient-not-exact)
323 finally (return (make-polynomial :terms q :var main-var))))
324 (t (quotient-not-exact))))
327 (defun afp-test-divide (f g &aux ( *testing* t) quot)
328 (declare (special *testing*))
329 (catch 'quotient-not-exact (setq quot (afp-quotient f g)))
330 (cond (quot quot)
331 (t nil)))
333 (defun afc-remainder (n divisor)
334 (multiple-value-bind (q r) (truncate n divisor) (values r q)))
336 ;;pseudo division as in Knuth's book.
338 (defun afp-pseudo-quotient (f g &aux (creqd 1))
339 "This function returns the values: quotient, remainder and creqd ~
340 so that creqd*f=g*quotient+remainder. Creqd does not involve the
341 main variable of f. The remainder has degree lower than g with respect
342 to the main variable of f."
343 (cond ((numberp f)
344 (cond ((numberp g)
345 (apply #'values (append '(1) (multiple-value-list (afc-remainder f g)))))
346 (t (values 0 f 1))))
347 ((numberp g)
348 (values f 0 g))
349 ((pointergp (p-var f) (p-var g))
350 (values f 0 g))
351 ((eq (p-var f) (p-var g))
352 (loop with quot with deg-dif with main-var = (p-var f)
353 with remainder =
354 (cond ((and (numberp (p-cof g)) modulus) f)
355 ((and (numberp (p-cof g))
356 (eql (abs (p-cof g)) 1)) f)
357 (t (ptimes f (setq creqd (pexpt (p-cof g)
358 (+ 1 (- (p-deg f) (p-deg g))))))))
360 (setq deg-dif (- (p-deg remainder) (p-deg g)))
361 while (>= deg-dif 0)
362 collecting deg-dif into q
363 collecting (setq quot (afp-quotient (p-cof remainder) (p-cof g)))
364 into q
366 (setq remainder (pplus
367 remainder
368 (term-operation g
369 ;;-fn/gm
370 (pminus quot)
371 ptimes deg-dif)))
372 while (and (not (numberp remainder))
373 (eql (p-var remainder) main-var))
374 finally
375 (setq quot (make-polynomial :terms q :var main-var))
376 ; (iassert (eql 0 (pdifference (ptimes f creqd ) (Pplus remainder (ptimes quot g)))))
377 (return (values quot remainder creqd))))
378 (t (values 0 f 1))))
380 (defmacro assume-pointerg-or-equal-p (f g &optional reverse-flag)
381 `(cond (( gen-pointergp ,f ,g) nil)
383 ,@ (cond (reverse-flag (list `(setq ,reverse-flag (null ,reverse-flag)))))
384 (rotatef ,f ,g))))
386 (defun gen-pointergp (f g)
387 (cond ((numberp g) t)
388 ((numberp f) nil)
389 (t (pointergp (p-var f) (p-var g)))))
391 (defun gen-degree (f)
392 (cond ((numberp f) 0)
393 (t (p-deg f))))
395 (defmacro assume-greater-equal-degree (f g &optional reverse-flag)
396 `(cond ((>= (gen-degree ,f) (gen-degree ,g)) nil)
398 ,@ (cond (reverse-flag (list `(setq (,reverse-flag (null ,reverse-flag))))))
399 (rotatef ,f ,g))))
402 (defun afp-content (f )
403 "Returns the gcd of the coefficients of f (with respect to the main variable) ~
404 if f is a polynomial"
405 (cond ((numberp f) f)
406 (t (loop for (deg cof) on (cdddr f) by #'cddr
407 with cont = (p-cof f)
408 do (setq cont (afp-gcd cont cof))
409 finally (return cont)))))
411 (defun principal-part (f)
412 (afp-quotient f (afp-content f)))
414 (defvar *afp-gcd* 'subresultant)
416 (defun afp-gcd (f g &aux answer)
417 "Returns the gcd of its two arguments which may be any polynomial ~
418 with integer coefficients. "
419 (setq answer
420 (case *afp-gcd*
421 (euclidean (afp-euclidean-gcd f g))
422 (subresultant (afp-subresultant-gcd f g))
423 (t (merror "~%The value of the switch *afp-gcd* ~A is not legal." *afp-gcd*))))
424 (cond (modulus (afp-try-make-monic answer))
425 (t answer)))
427 ;;This is the Euclidean gcd algorithm, as in Knuth.
428 (defun afp-euclidean-gcd (f g &aux u v r d contf contg)
429 "Returns the gcd of its two arguments which may be any polynomial ~
430 with integer coefficients. Currently uses the Euclidean algorithm, but should
431 have a switch"
432 (assume-pointerg-or-equal-p f g)
433 (cond ((numberp f)(gcd f g))
434 ((gen-pointergp f g)
435 (afp-gcd (afp-content f) g))
436 ; (loop for (deg cof) on (p-terms f) by #'cddr
437 ; with gcd = g
438 ; do (setq gcd (afp-gcd cof gcd))
439 ; finally (return gcd)))
440 ((eq (p-var f) (p-var g))
441 (setq d (afp-gcd
442 (setq contf (afp-content f))(setq contg (afp-content g))))
443 (setq u (afp-quotient f contf))
444 (setq v (afp-quotient g contg))
445 (assume-greater-equal-degree u v)
446 (loop with unused
447 do (multiple-value-setq (unused r) (afp-pseudo-quotient u v))
448 when (pzerop r)
449 do (return (ptimes d v))
450 when (gen-pointergp f r)
451 do (return d)
452 do (setq u v)
453 (setq v (afp-quotient r (afp-content r)))))
454 (t (fsignal 'should-not-get-here))))
457 ;;This was about twice as fast as the regular maxima pgcd on
458 ;;some simple functions: 121 msec. as opposed to 250 msec.
459 ;;this was with the afp-content in terms of the old afp-gcd.
460 ;; (afp-subresultant-gcd-compare (st-rat #$8*3*(x^2+1)*(x+1)*(z^2+2)*(x+2)$)(st-rat #$15*(x^2-1)*(x^2+1)*(y^2+4)*(z^4+2*z+1)$))
461 ;(user:compare-recursive-functions
462 (defun afp-subresultant-gcd (f g &aux delta u v r d contf contg answ)
463 "Returns the gcd of its two arguments which may be any polynomial ~
464 with integer coefficients. It uses the subresultant algorithm"
465 (assume-pointerg-or-equal-p f g)
466 (cond ((numberp f)(gcd f g))
467 ((gen-pointergp f g)
468 (cond ((pzerop g) f)
470 (afp-subresultant-gcd (afp-content f) g))))
471 ((eq (p-var f) (p-var g))
472 (setq d (afp-subresultant-gcd
473 (setq contf (afp-content f))
474 (setq contg (afp-content g))))
475 (setq u (afp-quotient f contf))
476 (setq v (afp-quotient g contg))
477 (assume-greater-equal-degree u v)
478 (setq answ (loop with gg = 1 with h = 1 with g^delta with unused
480 (setq delta (- (p-deg u) (p-deg v)))
481 (multiple-value-setq (unused r) (afp-pseudo-quotient u v))
482 when (pzerop r)
483 do (return (ptimes d (principal-part v)))
484 when (gen-pointergp f r)
485 do (return d)
486 do (setq u v)
487 (setq v (afp-quotient r (ptimes gg (pexpt h delta))))
488 (setq gg (p-cof u))
489 (setq g^delta (pexpt gg delta))
490 (setq h (cond ((eql delta 1) g^delta)
491 ((> delta 1) (afp-quotient g^delta
492 (pexpt h (- delta 1))))
493 ;;here delta=0
494 (t (ptimes g^delta h))))))
495 (afp-try-make-monic answ))))
498 (defun one-ptimes (f g)
499 (cond ((eql f 1) g)
500 ((eql g 1) f)
501 (t (ptimes f g))))
503 (defun exponent-product (&rest alternating-factor-exponent-list)
504 "Exponents may be positive or negative, but assumes result is poly"
505 (loop for (fact deg) on alternating-factor-exponent-list by #'cddr
506 with numer = 1 with denom = 1
507 when (= deg 1)
508 do (setq numer (one-ptimes numer fact))
509 else
510 when (> deg 1)
511 do (setq numer (one-ptimes numer (pexpt fact deg)))
512 else
513 when (= deg -1)
514 do (setq denom (one-ptimes denom fact))
515 else
516 when (< deg -1)
517 do (setq denom (one-ptimes denom (pexpt fact (- deg))))
518 finally (return (afp-quotient numer denom))))
520 (defun same-main-and-degree (f g)
521 (cond ((numberp f)(numberp g))
522 ((numberp g)(numberp f))
524 (and (eq (car f) (car g))
525 (eq (second f) (second g))))))
526 ;;unfinished.
527 ;(defun afp-sqfr (f &aux deriv d)
528 ; (cond ((numberp f) f)
529 ; (t
530 ; (loop
531 ; do
532 ; (setq deriv (pderivative f (p-var f)))
533 ; (setq d (afp-gcd f deriv))
534 ; (cond ((numberp d ) f)
535 ; ((same-main-and-degree d f)
536 ; (make-polynomial :var (p-var f)
537 ; :teerms
538 ; (loop for (deg cof) on (cdr f) by #'cddr
539 ; collecting (quotient deg modulus)
540 ; collecting cof)))
541 ; (t (setq f (afp-quotient f d))))))))
543 (defun afp-big-gcd (f g &aux tem)
544 "The arguments may be polynomials with integer coefficients. ~
545 Three values are returned: gcd , f/gcd, and g/gcd."
546 (values (setq tem (afp-subresultant-gcd f g)) (afp-quotient f tem) (afp-quotient g tem)))
548 (defun afp-pgcdcofacts (f g)
549 (multiple-value-list (afp-big-gcd f g)))
550 ;;this used 3 times the space and was much slower for the (x+y+z)^10
551 ;;problem but if I put z=1 then it went much faster, and used less
552 ;;space, but still not as good as the subresultant algorithm. It was
553 ;;about as fast as my subresultant algorithm.
554 ;(defun afp-big-gcd (f g)
555 ; (declare (values gcd-of-f-g f-over-gcd g-over-gcd))
556 ; (apply 'values (pgcdcofacts f g)))
558 #+debug
559 (defun test (f g)
560 (multiple-value-bind (d qf qg)
561 (afp-big-gcd f g)
562 (iassert (equal f (ptimes d qf))) (iassert (equal g (ptimes d qg)))))
564 (defun afp-square-free-with-modulus (u &aux (vari (list-variables u)) root deriv quot agcd)
565 (check-arg vari (null (cdr vari)) "univariate when modulus")
566 (check-arg modulus (primep modulus) "prime")
567 (cond ((numberp u) u)
568 (t (setq agcd (afp-gcd u (setq deriv (pderivative u (p-var u)))))
569 (cond ((numberp agcd) (list u 1))
570 ((> (p-deg u) (p-deg agcd))
571 (setq quot (afp-quotient u agcd))
572 (append (afp-square-free-with-modulus quot) (afp-square-free-with-modulus
573 agcd)))
574 ;;deriv is 0
575 (t (check-arg deriv (eql 0 deriv) "zero")
576 (setq root (psimp (p-var u)
577 (loop for (deg cof) on (cdr u) by #'cddr
578 collecting (quotient deg modulus)
579 collecting cof)))
580 (loop for (pol deg) on (afp-square-free-with-modulus root) by #'cddr
581 collecting pol collecting (* deg modulus)))))))
583 ;;timing on factoring the (x+y+z)^10 2.6 sec 10,047 words
584 ;;timing on factoring the (x+y+z)^20 20.2 sec 37,697 words
586 (defun afp-square-free-factorization (u &aux d tx v1 w1 some-factors unit)
587 "returns an alternating list of factors and exponents. In the characteristic 0 case each factor is ~
588 guaranteed square free and relatively prime to the other factors. Note that if
589 modulus is not zero then u should be univariate. Otherwise for eg mod 3, x^3-t
590 is not square free in the field with cube root of t adjoined, and it can't be factored
591 in Z/3Z[x,t]."
592 (cond (modulus
593 (afp-square-free-with-modulus u))
595 (cond ((numberp u)
598 (setq d (afp-content u))
599 (setq u (term-operation u d afp-quotient))
600 (multiple-value-setq (tx v1 w1)
601 (afp-big-gcd u (pderivative u (p-var u))))
602 ; (show tx v1 w1)
603 (setq some-factors
604 (cond ((eql tx 1)
605 (list u 1))
606 ((numberp tx)
607 (fsignal 'how-did-this-happen))
609 (loop for i from 1
610 with vi = v1 with wi = w1 with videriv with vi+1 with ui with wi+1
611 with main-var = (p-var u)
612 do ; (show i)
613 (setq videriv (pderivative vi main-var))
614 ; (show factor-list)
615 when (equal wi videriv)
617 (return (append factor-list (list vi i)))
619 (multiple-value-setq (ui vi+1 wi+1)
620 (afp-big-gcd vi (pdifference wi
621 videriv)))
622 ; (show vi wi ui vi+1 wi+1)
623 when (not (eql ui 1))
624 nconc (list ui i) into factor-list
626 (setq vi vi+1)
627 (setq wi wi+1)
628 ))))
629 ; (show some-factors)
630 ;;this is all to collect some numbers and fix the unit multiple.
631 (loop for (pol deg) on some-factors by #'cddr
632 with answ = d
633 do (setq answ (ptimes answ (pexpt (p-cof pol) deg)))
634 finally
635 (setq unit (afp-quotient (p-cof u) answ))
636 (cond ((eql unit 1) nil)
637 ((eql unit -1) (loop for (pol1 deg1) on some-factors by #'cddr
638 for i from 0 by 2
639 when (oddp deg1) do (setf (nth i some-factors)
640 (pminus pol1))
641 (return 'done)
642 finally (merror "no odd factors yet differs by minus ")))
643 (t (fsignal "not handled yet"))))
644 (cond ((eql d 1) some-factors)
645 (t (append (afp-square-free-factorization d) some-factors))))))))
649 ;;tested on (x+y+z)^10 times itself and got about
650 ;;the same time as ptimes 3100 milliseconds. in temporary area.
651 ;;It used 10% more space. 205,000 for (x+y+z)^20*(x+y+z)^10 for ptimes.
652 ;;note on the st-rat form it only takes 510 msec. for (x+y+z)^10 and
653 ;;2.00 sec for (x+y+z)^20 as opposed to 3 sec and 15 sec resp with
654 ;;;50000
655 ; afp-square-free-factorization pfactor
656 ; poly (x+y+z)^10 cre .51 7,887 3.0 17000
657 ; poly (x+y+z)^10 general 1.8 28,00 4.5 68,000
658 ; poly (x+y+z)^20 cre 2.0 28,000 15. 252,000
659 ; poly (x+y+z)^20 general 7.2 105,000 20.8 325,000
662 ;(compare-functions
663 ;(defun af-fake-times (f g)
664 ; (user:tim (progn (afp-times f g) nil)))
665 ;(defun reg-fake-times (f g)
666 ; (user:tim (progn (ptimes f g) nil)))
670 ;;essentially same speed as regular ptimes or maybe 5 %faster
671 ;;does (afp-times (x+y+z)^10 times itself in 2530 msec. and 2640 for ptimes.
674 (defun afp-times (f g)
675 "The two arguments are polynomials and the result is the product polynomial"
676 (cond ((numberp f)
677 (cond ((zerop f) 0)
678 (t (afp-pctimes g f ))))
679 ((numberp g)
680 (cond ((zerop g) 0)
681 (t(afp-pctimes f g))))
682 ((eq (p-var f) (p-var g))
683 (palgsimp (p-var f) (afp-terms-times (cdr f)(cdr g)) (alg f)))
684 ((pointergp (p-var f) (p-var g))
685 (psimp (p-var f) (plain-term-operation (cdr f) g afp-times)))
686 (t(psimp (p-var g) (plain-term-operation (cdr g) f afp-times)))))
689 ;;;the following shuffles the terms together and is about the same speed as the
690 ;;;corresponding maxima function ptimes1
691 ;(defun afp-terms-times (terms-f terms-g &aux prev to-add repl new-deg one-product)
692 ; "assumes same main variable"
693 ; (loop while terms-f
694 ; do
695 ; (setq one-product
696 ; (plain-term-operation terms-g (term-cof terms-f) afp-times (term-deg terms-f)))
697 ; until one-product
698 ; do (setq terms-f (cddr terms-f)))
699 ; (cond ((null one-product) nil)
700 ; (t
701 ; (loop for (deg-f cof-f) on (cddr terms-f) by 'cddr
702 ; do
703 ; (loop for (deg cof) on terms-g by #'cddr ;;sue
704 ; ;;computes the coeff of x^deg+deg-g and adds it in to
705 ; ;;the terms of one-product. Prev stands for the terms beginning
706 ; ;;with where the previous one was added on, or
707 ; initially
708 ; (setq prev one-product)
709 ; do (setq new-deg (+ deg deg-f))
710 ; (setq to-add (afp-times cof-f cof))
711 ; (cond ((pzerop to-add))
712 ; ;;you should only get here when not in an integral domain
713 ; ((>= new-deg(car prev))
714 ; (cond ((> new-deg (car prev))
715 ; (setq one-product (setq prev (cons new-deg (cons to-add prev)))))
716 ; (t
717 ; ;;claim this can't happen unless prev = one-product
718 ; ;;Since otherwise have had a non-trivial to-add already in the sue
719 ; ;;loop and this would have added something in degree new-deg, but back
720 ; ;;one step, and prev would have that new-deg as its first element.
721 ; ;;That new-deg must be bigger than the current new-deg.
722 ; (iassert (eq prev one-product))
723 ; (cond ((pzerop (setq repl (afp-plus (term-cof prev) to-add)))
724 ; (setq prev (setq one-product (cddr prev))))
725 ; (t(setf (second prev) repl))))))
726 ; (t ;;each to-add term has lower new-deg than the previous (or to-add=0)
727 ; (loop for vvv on (cddr prev) by #'cddr
728 ; do
729 ; (cond ((> (term-deg vvv) new-deg) (setq prev vvv))
730 ; ((eql (term-deg vvv) new-deg)
731 ; (cond ((pzerop (setq repl (afp-plus (term-cof vvv) to-add)))
732 ; (setf (cddr prev)(cddr vvv)))
733 ; (t (setf (term-cof vvv) repl)
734 ; (setq prev (cddr prev))))
735 ; (return nil))
736 ; (t (setf (cddr prev) (cons new-deg (cons to-add vvv)))
737 ; (setq prev (cddr prev))
738 ; (return nil)))
739 ; finally (setf (cddr prev)(list new-deg to-add))))))
740 ; finally (return one-product)))))
743 (defun test-decrease (terms)
744 (loop for (deg cof) on terms by #'cddr
745 with d0 = 1000
746 when (not (> d0 deg)) do (fsignal 'bad-order)
747 else do (setq d0 deg)))
749 (defun afp-pctimes (poly number)
750 "Its first argument must be a polynomial and second argument a number,~
751 and it returns the product"
752 (cond ((atom poly)(ctimes poly number))
753 (t (term-operation poly number afp-pctimes))))
755 (defmacro butlastn (n list)
756 "knocks off the last n items of a list"
757 `(setf ,list (cond ((< ,n (length ,list))
758 (setf (cdr (lastn (1+ ,n) ,list)) nil) ,list)
759 (t nil))))
761 (defun test-times (f g &key empty)
762 (cond (modulus (iassert (equal (tim (afp-times f g))
763 (remove-zero-coefficients (tim (ptimes f g))))))
764 (empty (tim (progn
765 (afp-times f g)
766 nil))
767 (tim (progn
768 (ptimes f g)
769 nil)))
770 (t (iassert (equal (tim (afp-times f g))
771 (tim (ptimes f g)))))))
774 (defun remove-zero-coefficients (poly)
775 (cond ((numberp poly)poly)
776 (t (loop with v = poly
777 while (cdr v)
778 do (setf (third v) (remove-zero-coefficients (third v)))
779 when (pzerop (third v))
780 do(setf (cdr v) (cdddr v))
781 else
782 do (setq v (cddr v))
783 finally (return (cond ((null (cdr poly)) 0)
784 ((zerop (second poly))(third poly))
785 (t poly)))))))
787 (defun recursive-ideal-gcd1 (f g )
788 "assumes that f and g are polynomials of one variable and that modulus is non trivial
789 and that deg f >= deg g gcd = a*f +b*g , and deg a < deg g, deg b < deg f"
790 (cond ((numberp g)(setq g (cmod g))
791 (cond ((zerop g)(values f 1 0))
792 (t (values 1 0 (crecip g)))))
793 ((not (eql (p-var g) (p-var f)))(merror 'not-function-of-one-variable))
794 (t(multiple-value-bind (quot zl-rem creqd)
795 (afp-pseudo-quotient f g)
796 creqd ;;ignore
797 (multiple-value-bind (gcd a b)
798 (recursive-ideal-gcd1 g zl-rem)
799 (values gcd b (pdifference a (ptimes quot b))))))))
803 (defun recursive-ideal-gcd (f g &aux rev? fact)
804 "assumes that f and g are polynomials of one variable and that modulus is non trivial
805 It returns (gcd a b) such that gcd = a*f +b*g , and deg a < deg g, deg b < deg f where
806 gcd is the gcd of f and g in the polynomial ring modulo modulus."
807 (cond ((null modulus) (merror "polynomials over the integers are not a PID")))
808 (assume-pointerg-or-equal-p f g rev?)
809 (cond ((numberp f)(values 1 (crecip f) 0))
810 (t (multiple-value-bind (gcd a b)
811 (recursive-ideal-gcd1 f g)
812 ; (iassert (zerop (pdifference gcd (pplus (ptimes f a) (ptimes g b)))))
813 ; (iassert (numberp (afp-quotient gcd (pgcd f g))))
814 (cond ((numberp gcd)
815 (cond ((not(equal gcd 1))(setq fact (crecip gcd)))))
816 (t (cond ((not(equal (p-cof gcd) 1))(setq fact (crecip (p-cof gcd)))))))
817 (cond (fact (setq gcd (ptimes fact gcd))
818 (setq a (ptimes a fact))
819 (setq b (ptimes b fact))))
820 (cond (rev? (values gcd b a))
821 (t (values gcd a b)))))))
825 (defvar $e_poles nil)
827 ;;;do the following at macsyma level to specify which poles you want:
828 ;;; e_poles:[e^-2,e^-1]$
830 (defun $list_poles_of_sum (sum)
831 (cond ((numberp sum) '((mlist simp) 0 0))
833 (check-arg sum (and (consp sum)(eql (caar sum) 'mplus)) "macsyma sum")
834 (let ((pol $e_poles))
835 (cons (car pol) (loop for u in (cdr pol)
836 collecting
837 (loop for v in (cdr sum)
838 when (equal u v)
839 collecting 1 into cof
840 else
841 when (and (listp v) (member u (cdr v) :test 'equal))
842 collecting
843 (cond ((eql (length v) 3)
844 (loop for vv in (cdr v )
845 when (not (equal vv u))
846 do (return vv)))
847 (t (loop for vv in v
848 when (not (equal vv u))
849 collecting vv)))
850 into cof
851 finally (return (cond ((null cof) 0)
852 ((eql (length cof) 1) (car cof))
853 (t (apply 'add* cof)))))))))))
855 (defun constant-psublis (alist polynomial)
856 (setq alist (sort alist #'pointergp :key #'car))
857 (constant-psublis1 alist polynomial))
859 (defun constant-psublis1 (alist polynomial)
860 (cond ((numberp polynomial) polynomial)
861 ((null alist) polynomial)
863 (block sue
864 (prog
865 (main-var tem)
866 (setq main-var (p-var polynomial))
867 reduce-subs
868 (cond ((and alist (pointergp (caar alist) main-var))
869 (setq alist (cdr alist)) (go reduce-subs)))
870 (cond ((null alist) (return polynomial))
871 ((eql (caar alist) main-var)
872 (loop for (deg cof) on (p-next-term (p-terms polynomial))
873 by #'p-next-term
874 with repl = (cdr (car alist))
875 with answ = (afp-pctimes
876 (constant-psublis1
877 (cdr alist) (p-cof polynomial))
878 (cexpt repl (p-deg polynomial)))
879 do (setq answ
880 (pplus answ
881 (cond ((zerop deg)
882 (constant-psublis1 (cdr alist) cof))
883 (t (afp-pctimes (constant-psublis1
884 (cdr alist) cof)
885 (cexpt repl deg))))))
886 finally (return-from sue answ)))
887 (t (return
888 (psimp main-var
889 (loop for (deg cof)
890 on (p-terms polynomial) by #'p-next-term
891 unless (pzerop (setq tem (constant-psublis1 alist cof)))
892 nconc (list deg tem)))))))))))
894 ;;afp-pcsubsty used 1/2 space and was twice as fast as pcsubsty on substituting for one variable y
895 ;;in (x+y+z)^10 (33.5 msec. and 70 msec respect).
897 ;(compare-functions
898 ;(defun afp-pcsubsty (vals vars pol)
899 ; (constant-psublis (subs-for-psublis vars vals) pol))
900 ;(defun reg-pcsubsty (vals vars pol)
901 ; (pcsubsty vals vars pol)))
903 (defun my-evenp (n &aux nn)
904 (setq nn (ash n -1))
905 (and (equal (ash nn 1) n) nn))
907 ;;On symbolics the regular gcd is only 40% of the speed of fast-gcd.
908 ;;and I compared the values on several hundred random
909 ;;m n and it was correct.
910 ;;on (test 896745600000 7890012 1000) of 1000 repeats
911 ;;the fast-gcd was .725 sec and the regular gcd was 5.6 sec. using 0 and 23000 words resp.
912 ;;On Explorer: Release 1.0)the fast-gcd was 1.9 sec and the regular gcd was .102 sec. using 0 and 0 words resp.
913 ;(defun test (m n rep &aux a b)
914 ; (tim (loop for i below rep
915 ; do (setq a (fast-gcd m n))))
916 ; (tim (loop for i below rep
917 ; do (setq b (\\\\ m n))))
918 ; (assert (equal a b)))
919 ;;for testing two gcd's give same results.
920 ;(defun test ( rep &aux m n a b)
921 ; (loop for i below rep
922 ; do (setq m (* (random (expt2 32))(setq n (random (^ 2 32)))))
923 ; when (oddp i) do(setq n (- n))
924 ; do
925 ; (setq n (* n (random (^ 2 32))))
926 ; do (setq a (gcd m n))
927 ; do (setq b (\\\\ m n))
928 ; (show (list m n a))
929 ; (assert (equal a b))))
932 (defun fast-gcd (m n)
933 (setq m (abs m) n (abs n))
934 (cond ((< n m)nil)
935 (t (rotatef m n)))
936 (cond ((zerop n) m)
937 ((fixnump n)
938 (setq m (mod m n))
939 (cond ((zerop m) n)
940 (t (bin-gcd m n))))
941 (t (gcd n (mod m n)))))
944 (defun bin-gcd (u v &aux (k 0)u2 v2 t2 tt)
945 (loop
946 do (setq u2 (ash u -1))
947 when (not (eql (ash u2 1) u))
948 do (return k)
949 do (setq v2 (ash v -1))
950 when (not (eql (ash v2 1) v))
951 do (return k)
952 do (setq u u2 v v2 k (1+ k)))
953 (prog ()
955 (cond ((oddp u) (setq tt (- v)))
956 (t (setq tt (ash u -1))))
957 b3b4
958 (loop do (setq t2 (ash tt -1))
959 when (eql (ash t2 1) tt)
960 do (setq tt t2)
961 else do (return nil))
962 (cond ((> tt 0) (setq u tt))
963 (t (setq v (- tt))))
964 (setq tt (- u v))
965 (cond ((zerop tt)(return (ash u k)))
966 (t (go b3b4)))))
968 (defun poly-length (poly)
969 (cond ((numberp poly ) 0)
970 (t (length (cdr poly)))))
972 (defun poly-to-row (poly &optional row &aux leng)
973 (cond (row
974 (cond ((< (array-total-size row) (length poly))
975 (setq row (adjust-array row (+ 10 (poly-length poly)) :fill-pointer (fill-pointer row))))))
977 (setq row (make-array (+ 10 (setq leng (poly-length poly))) :fill-pointer 0 :adjustable t))))
978 (cond ((numberp poly)
979 (vector-push 0 row)
980 (vector-push poly row))
982 (loop for u in (cdr poly) do
983 (vector-push u row))))
984 row)
986 (defun row-to-terms (row)
987 (listarray (sort-grouped-array row 2 '>)))
989 ;;seems afp-square is roughly twice as fast on univariate.
990 ;(user:compare-recursive-functions
992 (defun afp-square (poly)
993 (cond ((numberp poly)(ctimes poly poly))
994 (t (palgsimp (p-var poly) (afp-terms-square (p-terms poly)) (alg poly)))))
996 ;;comparison for squaring (x+y+z)^10 and (x+y+z)^4 (x+1)^10
997 ;;;done in temp area:
998 ; afp-square (time space) pexpt (time space)
999 ;(x+y+z)^10 1450 ms. 25,305 1780ms 32,270
1000 ;(x+y+z)^4 80 ms. 1,443 111ms 2,099
1001 ;(x+1)^10 82 ms. 527 190ms 2,911
1003 ;; (defun test-square (f &key empty)
1004 ;; (cond (modulus
1005 ;; (iassert (equal (tim (afp-square f)) (remove-zero-coefficients (tim (pexpt f 2 ))))))
1006 ;; (empty
1007 ;; (tim (progn
1008 ;; (afp-square f)
1009 ;; nil))
1010 ;; (tim (progn
1011 ;; (pexpt f 2)
1012 ;; nil)))
1013 ;; (t
1014 ;; (iassert (equal (tim (afp-square f)) (tim (pexpt f 2)))))))
1016 ;; (defun test-square (f &key empty)
1017 ;; (cond (modulus
1018 ;; (iassert (equal (tim (afp-square f)) (remove-zero-coefficients (tim (ptimes f f))))))
1019 ;; (empty
1020 ;; (tim (progn
1021 ;; (afp-square f)
1022 ;; nil))
1023 ;; (tim (progn
1024 ;; (pexpt f 2)
1025 ;; nil)))
1026 ;; (t
1027 ;; (iassert (equal (tim (afp-square f)) (tim (ptimes f f)))))))
1029 ;;pexpt is not accurate for modulus=9
1030 ;;note example set al:(x+y+z)^4 in polynomial form.
1031 ;;then (let ((modulus 9)) (equal (ptimes al al) (pexpt al 2))) ==> nil
1032 ;;but afp-square does work.
1034 (defun afp-terms-square (p-terms)
1035 (prog (lead orig-p2-terms p2-terms prod-exp prod-cof tail answ)
1036 begin
1037 (cond (p-terms (setq answ (afp-square (term-cof p-terms)))
1038 (setq orig-p2-terms(setq p2-terms (plain-term-operation (cddr p-terms) 2 afp-pctimes)))
1039 (setq answ (plain-term-operation p2-terms (term-cof p-terms) afp-times (term-deg p-terms)))
1040 (setq lead (afp-square (term-cof p-terms)))
1041 (cond ((pzerop lead) nil)
1042 (t (setq answ (cons (* 2 (term-deg p-terms))
1043 (cons lead
1044 answ)))))
1045 (cond ((null answ)
1046 (setq p-terms (cddr p-terms))
1047 (setq p2-terms (cddr p2-terms))
1048 (go begin))
1049 (t (go second-leading-square))))
1050 (t (return nil)))
1051 tail-certain ;;add in term to tail
1052 (cond ((and (cdr tail)(> (second tail) prod-exp))
1053 (setq tail (cddr tail)) (go tail-certain)))
1054 (cond ((or (null (cdr tail))(< (second tail) prod-exp))
1055 (setf (cdr tail) (cons prod-exp (cons prod-cof (cdr tail))))
1056 (setq tail (cddr tail)) (go next-double-product)))
1057 (cond ((pzerop (setq prod-cof (pplus (third tail) prod-cof)))
1058 (setf (cdr tail) (cdddr tail)))
1059 (t (setf (third tail) prod-cof) (setq tail (cddr tail))))
1060 next-double-product
1061 (setq p2-terms (cddr p2-terms))
1062 (cond ((null p2-terms)(go next-leading-square)))
1063 (setq prod-cof (afp-times (term-cof p-terms) (term-cof p2-terms)))
1064 (cond ((pzerop prod-cof) (go next-double-product)))
1065 (setq prod-exp (+ (term-deg p-terms) (term-deg p2-terms)))
1066 (go tail-certain)
1067 next-leading-square
1068 (setq orig-p2-terms (cddr orig-p2-terms))
1069 second-leading-square
1070 (setq p-terms (cddr p-terms))
1071 (cond ((null p-terms)(return answ)))
1072 (setq prod-cof (afp-square (term-cof p-terms)))
1073 (setq p2-terms orig-p2-terms)
1074 (setq tail (cdr answ))
1075 (cond ((pzerop prod-cof) (go next-double-product)))
1076 (setq prod-exp (* 2 (term-deg p-terms)))
1077 (go tail-certain)))
1080 (defmacro def-test (f1 f2)
1081 `(defun ,(intern (format nil "~A-~A" '#:test f1)) (&rest rest-args)
1082 (let (empty (*print-level* 2)(*print-length* 3) ansa ansb)
1085 (cond ((member ':empty rest-args :test #'eq)
1086 (setq rest-args (subseq rest-args 0 (- (length rest-args)
1087 (length (member ':empty rest-args :test #'eq)))))
1088 (setq empty t)))
1089 (format t "~%For functions ~A and ~A respectively, ~%with argument list being ~A" ',f1 ',f2 rest-args)
1090 (cond (empty (format t "~%All computations done in a temporary area:")))
1091 (cond ((and (null empty)modulus)
1092 (progn
1093 (iassert (equal (setq ansa(tim (apply ',f1 rest-args)))
1094 (setq ansb (remove-zero-coefficients (tim (apply ',f2 rest-args ))))))))
1095 (empty (tim (progn
1096 (apply ',f1 rest-args )
1097 nil))
1098 (tim (progn
1099 (apply ',f2 rest-args)
1100 nil)))
1101 (t (progn
1102 (iassert (equal (setq ansa (tim (apply ',f1 rest-args )))
1103 (setq ansb(tim (apply ',f2 rest-args)))))))))))
1105 ;;timings for afp-expt and pexpt respectively with 5 th power
1106 ;(x+y+z)^4
1107 ;For functions AFP-EXPT and PEXPT respectively,
1108 ;with argument list (POLY EXPONENT) being ((Z 4 1 ...) 5)
1109 ;All computations done in a temporary area:
1110 ;2223.207 msec. at priority 1
1111 ;Reclaiming 39,793 in polynomial space (total 4,176,070).14:20:53
1112 ;3029.429 msec. at priority 1
1113 ;Reclaiming 50,579 in polynomial space (total 4,226,649).14:20:56"
1115 ;(x+1)^10
1116 ;For functions AFP-EXPT and PEXPT respectively,
1117 ;with argument list (POLY EXPONENT) being ((X 10 1 ...) 10)
1118 ;All computations done in a temporary area:
1119 ;1972.551 msec. at priority 1
1120 ;Reclaiming 17,220 in polynomial space (total 3,825,741).14:19:00
1121 ;3312.806 msec. at priority 1
1122 ;Reclaiming 28,634 in polynomial space (total 3,854,375).14:19:03"
1124 ;;note ( pexpt (x+y+z)^4 5) yields false result.. if modulus is 4.
1125 ;;I checked that afp-expt was ok, by comparing to the following
1126 ;;simple exponent function.
1127 ;(def-test afp-expt pexpt-simple)
1128 ;(defun pexpt-simple (u n)
1129 ; (loop for i from 1 to n
1130 ; with answ = 1
1131 ; do (setq answ (ptimes answ u))
1132 ; finally (return answ)))
1133 (defun afp-expt-modulo (poly exponent &rest work-modulo)
1134 (working-modulo work-modulo
1135 (afp-expt poly exponent)))
1137 (defun afp-expt (poly exponent)
1138 "Raises the polynomial POLY to EXPONENT. It never performs more
1139 than a squaring before simplifying, so that if modulus or tellrat are
1140 in effect, it will still be reasonable."
1141 (cond ((eql exponent 1) poly)
1142 ((eql exponent 0) poly)
1143 ((< exponent 0) (merror "Use positive exponents"))
1144 (t (cond ((numberp poly)(cexpt poly exponent))
1145 ((or (cdddr poly) (alg poly))
1146 ;;main case
1147 (loop for i from 0
1148 with 2^i-power-poly = poly
1149 with answer = 1
1151 (cond ((oddp exponent)
1152 (cond ((eql answer 1)
1153 (setq answer 2^i-power-poly))
1155 (setq answer (afp-times answer 2^i-power-poly))))))
1157 (setq exponent (ash exponent -1))
1158 (cond ((zerop exponent)(return answer)))
1159 (setq 2^i-power-poly (afp-square 2^i-power-poly))))
1160 (t ;;monomial of variable not tellrated
1161 (let ((pow (afp-expt (p-cof poly) exponent)))
1162 (cond ((pzerop pow) 0)
1164 (psimp (p-var poly)
1165 (list (* (p-deg poly) exponent)
1166 pow))))))))))
1167 (defmacro push-poly-number-deg-cof (rows poly-number deg cof &aux (row (make-symbol "row")))
1168 `(let ((,row (aref ,rows ,deg)))
1169 (vector-push-extend ,poly-number ,row)
1170 (vector-push-extend ,cof ,row)))
1172 ;;want to find sol'ns of v^p-v=0 (mod u)
1173 (defun berlekamp-set-up-and-reduce-matrix ( u p &aux rows powers estimated-size sp)
1174 (setq rows (make-array (p-deg u) :fill-pointer (p-deg u)))
1175 (let ((modulus p)(tellratlist (list u)))
1176 (working-modulo (list u)
1177 (setq powers
1178 (loop for i from 0
1179 with pol = (afp-expt (list (p-var u) 1 1) p)
1180 with pow = 1 with belo = (1- (p-deg u))
1181 collecting pow
1182 while (< i belo)
1183 when (eql pow 1)
1184 do (setq pow pol)
1185 else do (setq pow (afp-times pol pow)))))
1186 (loop for i below (max 5 (length powers))
1187 for vv in powers
1188 summing (or (and (atom vv) 0) (length vv)) into count
1189 finally (setq estimated-size (+ 10 (quotient count 5))))
1190 (loop for i below (fill-pointer rows)
1191 do (setf (aref rows i) (make-array estimated-size :fill-pointer 0 :adjustable t)))
1192 ;;putting the entries in the sparse matrix. Each polynomial is a column.
1193 (loop for vv in (cdr powers)
1194 for i from 1
1195 when (numberp vv)
1197 (push-poly-number-deg-cof rows i 0 vv)
1198 (push-poly-number-deg-cof rows i i -1)
1199 else
1201 (loop for (deg cof) on (p-terms vv) by #'p-next-term
1202 with subtracted-it
1203 when (eql i deg)
1205 (setq cof (- cof 1))
1206 (setq subtracted-it t)
1208 (cond ((not (zerop cof))
1209 (push-poly-number-deg-cof rows i deg cof)))
1210 finally (cond ((null subtracted-it)
1211 (push-poly-number-deg-cof rows i i -1))))
1213 (setq sp (make-sparse-matrix :rows rows
1214 :type-of-entries p
1215 :columns-used-to-pivot (make-hash-table :test 'equal)))
1216 (sp-set-rows sp rows (loop for i from 1 below (p-deg u) collecting i))
1217 (sp-reduce sp)
1218 sp))
1220 (defun berlekamp-polynomial-solutions (sp polynomial &aux sp-sols)
1221 (sp-solve sp )
1222 (setq sp-sols (sp-solutions sp))
1223 (loop for i below (row-length (sp-rows sp-sols))
1224 collecting (psimp (p-var polynomial)(listarray (sort-grouped-array (sp-row sp-sols i) 2 '>)))))
1227 (defun berlekamp-get-factors-little-prime (u reduced-sparse-matrix prime &aux number-of-factors b-polys poly tem
1228 (factor-list (list u)))
1229 (setq number-of-factors (- (p-deg u) (sp-number-of-pivots reduced-sparse-matrix) ))
1230 (show number-of-factors)
1231 (sp-show-matrix reduced-sparse-matrix)
1232 (cond ((eql 1 number-of-factors) ;;irreducible
1233 factor-list)
1234 (t (setq b-polys (berlekamp-polynomial-solutions
1235 reduced-sparse-matrix u))
1236 (loop named sue
1237 for v in b-polys
1238 with half-p = (ash prime -1)
1240 (loop for j from (- half-p) to half-p
1242 (loop for u-fact in factor-list
1244 ;;make more efficient.
1245 (setq poly (pplus v j))
1246 (setq tem (afp-gcd poly u-fact))
1247 when (not (or (numberp tem)
1248 (eql (p-deg tem) (p-deg u-fact))))
1249 do (setq tem (afp-make-monic tem))
1250 (setq factor-list (cons tem
1251 (cons (afp-quotient u-fact
1252 tem)
1253 (delete u-fact factor-list :test #'equal))))
1254 when (eql (length factor-list) number-of-factors)
1255 do (return-from sue factor-list)))))))
1257 (defun berlekamp-get-factors-big-prime (u reduced-sparse-matrix prime &aux number-of-factors b-polys
1258 (factor-list (list u)))
1259 (setq number-of-factors (- (p-deg u) (sp-number-of-pivots reduced-sparse-matrix) ))
1260 (show number-of-factors)
1262 (cond ((eql 1 number-of-factors) ;;irreducible
1263 factor-list)
1264 (t (setq b-polys (berlekamp-polynomial-solutions
1265 reduced-sparse-matrix u))
1266 (prog (half-p tem pow v)
1267 (setq half-p (ash prime -1))
1268 added-factor
1269 (cond ((>= (length factor-list) number-of-factors)(return factor-list)))
1270 (setq v (loop for vv in (cdr b-polys)
1271 with answ = (afp-pctimes (car b-polys) (random (max 500 prime)))
1272 do (setq answ (pplus answ (afp-pctimes vv (random prime))))
1273 finally (return answ)))
1274 (working-modulo
1275 (list u)
1276 (setq pow (pdifference (afp-expt v half-p) 1)))
1277 (setq factor-list
1278 (loop for w in factor-list
1279 do (setq tem (afp-make-monic (afp-gcd pow w)))
1280 when (not (or (numberp tem)
1281 (eql (p-deg tem) (p-deg w))))
1282 collecting tem
1284 collecting (afp-quotient w tem)
1285 else collecting w))
1286 (go added-factor)))))
1288 (defun afp-make-monic (poly)
1289 (cond ((numberp poly) 1)
1290 ((not (or modulus (eql (abs (p-cof poly)) 1)))
1291 (merror "not finite modulus or unit coefficient"))
1292 (t (let ((inv (crecip (p-cof poly ))))
1293 (afp-pctimes poly inv)))))
1297 (defun afp-try-make-monic (poly)
1298 (cond ((numberp poly) 1)
1299 ((eql (p-cof poly) 1) poly)
1300 ((eql (p-cof poly) -1)
1301 (pminus poly))
1302 (modulus
1303 (cond ((numberp (p-cof poly))
1304 (afp-pctimes poly (crecip (p-cof poly))))
1305 (t poly)))
1306 (t poly)))
1308 (defun afp-berlekamp-factor (pol)
1309 (afp-berlekamp-factor1 pol modulus :use-little (<= modulus 13)))
1311 (defun afp-berlekamp-factor1 (pol p &key use-little use-big &aux sp (modulus p) answ)
1312 (setq sp (berlekamp-set-up-and-reduce-matrix pol p) )
1313 (cond ((and (null use-big)(or use-little (< p 13))) (setq answ (berlekamp-get-factors-little-prime pol sp p)))
1314 (t (setq answ (berlekamp-get-factors-big-prime pol sp p))))
1315 (loop for v in answ
1316 with ans = 1
1317 do (setq ans (ptimes ans v))
1318 finally (show ans) (iassert (equal (afp-mod pol) ans)))
1319 (show answ)
1320 (mapcar #'afp-mod answ))
1322 (defvar *mod-p-factor* 'afp-berlekamp-factor)
1323 ;(defvar *mod-p-factor* 'afp-distinct-degree-factor)
1325 (defvar *sort-factors* t)
1327 (defun afp-factor (pol &key square-free-arg &aux factor-function facts vars lead answ)
1328 (cond (modulus (setq lead (p-cof pol))
1329 (setq pol (afp-try-make-monic pol))))
1330 (cond (square-free-arg (setq facts (list pol 1)))
1331 (t(setq facts (afp-square-free-factorization pol))))
1332 (setq vars (list-variables pol))
1333 (setq answ (cond (modulus
1334 (cond ((cdr vars) (fsignal 'not-univariate))
1335 (t (setq factor-function *mod-p-factor* )
1336 (setq answ
1337 (loop for (pol deg) on facts by #'cddr
1338 with const = 1
1339 when (consp pol)
1340 appending
1341 (loop for fa in (funcall factor-function pol)
1342 collecting fa
1343 collecting deg) into all
1344 else do (setq const (ctimes const pol))
1345 (iassert (eql deg 1))
1346 finally (setq const (* lead const))
1347 (return(cond ((not (eql const 1))
1348 (cons const (cons 1 all)))
1349 (t all))))))))
1350 (t (fsignal 'not-yet-without-modulus))))
1351 (cond (*sort-factors* (sort-grouped-list answ 2 'alphagreatp))
1352 (t answ)))
1354 (defun afp-mod (pol)
1355 (afp-pctimes pol 1))
1357 (defun get-factors (u use-for-gcd p &aux tem)
1358 (let ((modulus p))
1359 (loop for w in use-for-gcd
1360 appending
1361 (loop for i below p
1362 when (not (numberp (setq tem (afp-gcd (pplus w i) u))))
1363 do (show i) and
1364 collecting (monize tem)))))
1367 (defun afp-distinct-degree-factor (u &optional ( prime modulus) &aux (v u )(ww (list (p-var u) 1 1)) (d 0) gd
1368 mon (modulus prime) answer)
1369 "U should be univariate and square free. Calculations are done modulo PRIME. It
1370 returns an alternating list of factors"
1371 (setq mon ww)
1372 (setq answer
1373 (loop do (cond ((numberp v) (return answ))
1374 ((> (* 2 (1+ d)) (p-deg v))(return (cons v answ))))
1375 (incf d)
1376 (working-modulo (list v) (setq ww(afp-expt ww prime)))
1377 (setq gd (afp-gcd (pdifference ww mon) v))
1378 (cond ((and (consp gd) (> d (p-deg gd)))(fsignal 'big)))
1379 when (not (numberp gd))
1381 (setq v (afp-quotient v gd))
1382 (and (consp v) (consp ww) (setq ww (palgsimp (p-var v) (cdr ww) (cdr v))))
1383 when (not (numberp gd))
1384 appending (one-degree-factors (afp-try-make-monic gd) d prime) into answ))
1385 (iassert (eql (p-deg u)
1386 (loop for v in answer
1387 summing (p-deg v) )))
1388 answer)
1390 #+debug
1391 (defun tel (u n p &aux (modulus p))
1392 (check-arg p (oddp p) "odd")
1393 (iassert (eql (p-deg u)
1394 (loop for v in answ
1395 summing (p-deg v) )))
1397 (eql (p-deg u) n))
1398 (defun one-degree-factors (u deg p &aux pow tt tem facts used-tt answ (modulus p))
1399 "assumes u has its irreducible factors of degree DEG and works modulo P. U should
1400 be univariate and square free. The result is thus just a list of the factors (powers
1401 are unnecessary"
1402 (check-arg p (oddp p) "odd")
1403 (cond((eql (p-deg u) deg)(setq answ (list u )))
1404 (t (setq pow (quotient (- (expt p deg) 1) 2))
1405 (setq facts (list u))
1406 (loop named sue for i from 1
1408 (loop do (setq tt (generate-t-for-one-degree-factors u deg p i))
1409 unless (or (numberp tt) (member tt used-tt :test #'equal))
1410 do (push tt used-tt) (return tt))
1411 (working-modulo (list u)
1412 (setq tt (afp-expt tt pow) ))
1413 (loop for v in facts
1415 (setq tem (afp-gcd v (pplus tt 1)))
1416 (cond ((not (or (numberp tem) (eql (p-deg tem) (p-deg v))))
1417 (cond ((eql (p-deg tem) deg)(push (afp-make-monic tem) answ))
1418 (t (push tem facts)))
1419 (cond ((eql (p-deg (setq tem (afp-quotient v tem))) deg)
1420 (push (afp-make-monic tem) answ))
1421 ; ((numberp tem))
1422 (t (push tem facts)))
1423 (setq facts (delete v facts :test #'equal))))
1424 when (null facts) do (return-from sue answ)))))
1425 (cond ((member 1 answ) (fsignal 'bad)))
1426 (iassert (eql (p-deg u)
1427 (loop for pol in answ
1428 when (and (consp pol))
1429 summing (p-deg pol) )))
1430 answ)
1432 (defun generate-t-for-one-degree-factors (u deg p i &aux tem)
1433 (cond ((< i 5)
1434 (list (p-var u) 1 1 0 (random p)))
1435 ((psimp (p-var u) (loop for j downfrom (setq tem (+ 1 (random (- (* 2 deg) 1)))) to 0
1436 ;;make semi sparse
1437 when (evenp (random 2))
1438 collecting j and collecting (1+ (random (1- p))))))))
1440 (defun ff (u &optional ( prime modulus) &aux fact1 facts)
1441 (let ((modulus prime))
1442 (setq facts (afp-square-free-factorization u))
1443 (sort-grouped-list
1444 (loop for (pol pow) on facts by #'cddr
1445 do (show pol pow)
1446 (setq fact1 (afp-distinct-degree-factor pol prime))
1447 appending
1448 (loop for ww in fact1
1449 collecting ww collecting pow))
1451 'alphagreatp)))
1453 (defun nnpfactor (pol)
1454 (sort-grouped-list (npfactor pol) 2 'alphagreatp))
1456 (def-test nnpfactor afp-factor)
1458 ;(setq w2 (st-rat #$x^2+91*x+11$))
1459 ;(setq v2 (st-rat #$x^2+19*x+11$))
1460 ;(setq v1 (let ((modulus 7)) (afp-mod v2)))
1461 ;(setq w1 (let ((modulus 7)) (afp-mod w2)))
1462 ;(setq prod (ptimes v2 w2))
1464 (defun hensel-lift (product v w prime up-to-size &aux a b gcd
1465 (facts (list v w)))
1466 "Lifts v and w which satisfy product=v*w mod(prime) to a list FACTS = (uu vv)
1467 satisfying product = uu*vv mod (up-to-size). Product, v, and w are assumed to
1468 have leading coefficient 1"
1469 ; (declare (values fact-pair power))
1470 (let ((modulus prime)) (multiple-value-setq (gcd a b)
1471 (recursive-ideal-gcd v w))
1472 (cond ((not (numberp gcd))(fsignal "must have gcd of factors a unit")))
1473 (check-arg v (eql 1 (afp-mod (p-cof v))) "monic"))
1474 (loop with power = 1
1475 do (setq power (* power prime))
1476 while (< power up-to-size)
1478 (setq v (car facts) ) (setq w (second facts))
1479 (setq facts (hensel-lift1 product v w power prime a b))
1480 finally (return (values facts power))))
1483 (defun gen-afp-times (&rest lis)
1484 (setq lis (delete 1 (copy-list lis) :test #'equal))
1485 (cond ((null lis) 1)
1486 ((null (cdr lis))(car lis))
1487 (t (afp-times (car lis) (cond ((cddr lis)
1488 (apply 'gen-afp-times1 (cdr lis)))
1489 (t (second lis)))))))
1491 (defun gen-afp-times1 (&rest lis)
1492 (cond ((null lis) 1)
1493 ((null (cdr lis))(car lis))
1494 (t (afp-times (car lis) (cond ((cddr lis)
1495 (apply 'gen-afp-times (cdr lis)))
1496 (t (second lis)))))))
1498 (defun smallest-power-bigger (p up-to)
1499 (loop with pow = p
1500 while (< pow up-to)
1501 do (setq pow (* p pow))
1502 finally (return pow)))
1504 (defun hensel-lift-list (product factor-list prime up-to-size &aux lift )
1505 (cond ((eql (length factor-list)1 ) (list product))
1506 ((eql (length factor-list) 2) (hensel-lift product (first factor-list)
1507 (second factor-list) prime up-to-size))
1508 (t (setq lift (hensel-lift product (first factor-list) (let((modulus prime))(apply 'gen-afp-times (cdr factor-list)))
1509 prime up-to-size))
1510 (cons (car lift) (hensel-lift-list (second lift) (cdr factor-list) prime up-to-size)))))
1512 (defun hensel-lift1 (product ve we prev-modulus prime &optional a b &aux dif h kk quot zl-rem creqd new-modulus gcd)
1513 "lifts u=ve*we mod (p^e) to u=ve+1*we+1 mod (p^e+1) with ve=ve+1 and we=we+1 mod (p^e+1)
1514 and deg(ve+1)<=deg(ve) deg(we+1)<=deg(we) and returns the list of ve+1 and we+1"
1515 ; (declare (values (list ve+1 we+1)))
1516 (setq new-modulus (* prime prev-modulus))
1517 (let ((modulus new-modulus)) (setq dif (pdifference product (ptimes ve we))))
1518 (cond ((pzerop dif)(list ve we))
1520 (let ((modulus prime) )
1521 (cond ((null a)
1522 (multiple-value-setq (gcd a b)
1523 (recursive-ideal-gcd ve we)))))
1524 (let ((modulus new-modulus))
1525 (setq h (ptimes b dif))
1526 (setq kk (ptimes a dif))
1527 (let ((modulus new-modulus))
1528 (multiple-value-setq ( quot zl-rem creqd)
1529 (afp-pseudo-quotient h ve)))
1530 (setq h zl-rem)
1531 (setq kk (pplus kk (ptimes quot we)))
1532 (list (pplus ve h) (pplus we kk))))))
1533 ;(let ((modulus (expt prime (1+ e)))) (values (pplus ve h) (pplus we kk))))
1536 (defun collect-number-factors (fact-list &aux answ)
1537 "Makes sure there are no factors with leading cof = -1 and collects all constants together
1538 and puts them first"
1539 (loop for (pol deg) on fact-list by #'cddr
1540 with constant = 1
1542 (cond ((numberp pol)
1543 (setq constant (ctimes constant (cexpt pol deg))))
1544 ((eql (p-cof pol) -1)
1545 (setq constant (ctimes constant (cexpt (p-cof pol) deg)))
1546 (setq pol (pminus pol))
1547 (setq answ (nconc answ (list pol deg))))
1548 (t(setq answ (nconc answ (list pol deg)))))
1549 finally (return
1550 (cond ((eql 1 constant) answ)
1551 (t (cons constant (cons 1 answ)))))))
1553 (defun integer-univariate-factor (poly &aux facts)
1554 "returns an alternating list of irreducible polynomials and their powers in the factorization over the integers
1555 there will be at most one factor which is a number and it will be to the first power. The other irreducible
1556 polynomials will be relatively prime"
1557 (setq facts (afp-square-free-factorization poly))
1558 (show facts)
1559 (collect-number-factors (loop for (pol deg) on facts by #'cddr
1560 appending (loop for pol1 in (integer-univariate-factor1 pol)
1561 collecting pol1 collecting deg))))
1563 ;;(defvar *small-primes* '(3 5 7 11 13 17 19)) ; overrides *small-primes* in src/ifactor.lisp; not used
1565 (defun find-small-prime-so-square-free (poly &optional (variable (p-var poly)) (prime-start 13)&aux deriv cof the-gcd)
1566 "finds a small prime P so that the roots of poly with respect to variable VARIABLE are distinct and so
1567 that poly has the same degree reduced modulo P. It will continue for ever if the input is not square free over
1568 the integers."
1569 (setq deriv (pderivative poly variable))
1570 (setq cof (pcoeff poly (list variable (pdegree poly variable) 1)))
1571 (cond ( (eql *mod-p-factor* 'afp-distinct-degree-factor)
1572 (setq prime-start (max prime-start 3))))
1573 (loop for p from prime-start
1574 when (> (- p prime-start) 500) do (format t "~%I hope you have given me a square free polynomial!!")
1575 when (and (q-primep p)
1576 (let ((modulus p))(and (not (pzerop (afp-mod cof)))
1577 (or (numberp (setq the-gcd (afp-gcd (afp-mod poly) (afp-mod deriv))))
1578 (not (member variable (list-variables the-gcd) :test #'eq))))))
1579 do (return p)))
1580 (defun integer-univariate-factor1 (pol &aux p ( up-to 1000) facts lifts mod)
1581 "Argument pol is square free"
1582 (setq p (find-small-prime-so-square-free pol ))
1583 (let ((modulus p)) (setq facts (afp-factor pol :square-free-arg t)))
1584 (setq mod (smallest-power-bigger p up-to))
1585 (setq facts (loop for (pol deg) on facts by #'cddr
1586 when (not (eql deg 1)) do (fsignal "bad-degree-for-square-free")
1587 collecting pol))
1588 (setq lifts (hensel-lift-list pol facts p up-to))
1589 (correct-factors pol lifts p mod))
1591 (defun sub-lists (leng list)
1592 "Returns list of ordered sublists of LIST of length LENG"
1593 (cond ((zerop leng) nil)
1594 ((eql 1 leng)(mapcar 'list list))
1596 (loop for v on list
1597 appending (loop for w in (sub-lists (1- leng) (cdr v))
1598 collecting (cons (car v) w))))))
1600 (defun correct-factors (pol factors p mod &aux tried d answ quot prod)
1601 "Given the factors FACTORS of polynomial POL modulo MOD, we determine
1602 what the factors are over the integers. It is assumed that MOD is sufficiently
1603 large so that any real factors of POL lie in the range -MOD/2 to MOD/2. Also
1604 POL is assumed square free so that the factors are listed without their multiplicities"
1606 (prog ()
1607 (setq d 1)
1608 look-for-factors
1609 (cond ((> (* d 2) (length factors))
1610 (push pol answ) (return answ)))
1611 (loop for v in (sub-lists d factors)
1612 when (member v tried :test #'equal)
1613 nconc nil
1614 else
1615 do (push v tried)
1616 (let ((modulus mod)) (setq prod (apply 'gen-ptimes v)))
1617 ; (setq prod (gen-afp-times (p-cof pol) prod))
1618 (cond ((setq quot (afp-test-divide pol prod))
1619 (setq pol quot)
1620 (push prod answ)
1621 (loop for vv in v
1622 do (setq factors (delete vv factors :count 1 :test #'equal)))
1623 (go look-for-factors)))
1624 finally (incf d)
1625 (go look-for-factors))))
1628 (defun q-primep (i &aux lis)
1629 (cond ((car (member i (setq lis '(2 3 5 7 11 13)))))
1630 ((evenp i) nil)
1631 ((loop for v in (cdr lis)
1632 when (zerop (mod i v))
1633 do (return t))
1634 nil)
1635 (t (primep i))))
1638 (defun test-integer-factor (pol &aux facts)
1639 (setq facts (integer-univariate-factor pol))
1640 (iassert (equal pol (apply 'exponent-product facts)))
1641 facts)
1643 (defun subs-translate-sublis ( point &optional inv)
1644 (cond (inv (loop for v in point
1645 when (not (pzerop (cdr v)))
1646 collecting (cons (car v)
1647 (pplus (list (car v) 1 1) (cdr v)))))
1649 (loop for v in point
1650 when (not (pzerop (cdr v)))
1651 collecting (cons (car v)
1652 (pdifference (list (car v) 1 1) (cdr v)))))))
1654 ;;change to a defremember. and then clear it when starting new problem.
1655 ;;or alternately don't really need to clear since the modulus is stored.
1656 (defun express-x^i (f g k &optional (modulus modulus) &aux a b zl-REM quot gc mon case0 cre)
1657 "f and g should be univariate and the leading coefficient of g invertible modulo modulus.
1658 A list of two coefficients (a b) are returned such that x^i= a*f + b*g and deg(a)< deg (g)"
1659 (check-arg modulus (not (null modulus)) "non-trivial")
1660 (cond ((eql k 0) (multiple-value-setq (gc a b)
1661 (recursive-ideal-gcd f g))
1662 (list a b))
1663 (t (setq case0 (express-x^i f g 0))
1664 (setq a (ptimes (car case0) (setq mon (list (car f) k 1))))
1665 (setq b (ptimes (second case0) mon))
1666 (multiple-value-setq (quot zl-rem cre) (afp-pseudo-quotient a g))
1667 (setq a zl-rem)
1668 (setq b (pplus b
1669 (ptimes quot f)))
1670 ;;(iassert (equal mon (afp-plus (afp-times f a) (afp-times g b))))
1671 (list a b))))
1673 ;(setq point (rerat '((z . 0) (y . 0) )))
1674 ;(setq u (st-rat #$zzx^4+zzx^3*(3-z)+zzx^2*((y-3)*z-y^2-13)
1675 ; +zzx*((y^2+3*y+15)*z +6)
1676 ; +(-y^3-15*y)*z-2*y^2-30$))
1677 ;(setq f (st-rat #$ (zzx^2+2)$))
1678 ;(setq g (st-rat #$zzx^2+3*zzx-15$))
1679 ;;the wr-lift worked for the above data
1681 ;;speed hacks: The following has two areas which can be improved
1682 ;; 1. should not truncate the polynomial, should multiply with truncation.
1683 ;; 2. should make express-x^i a defremember.
1684 (defun wr-lift (u fi gi up-to-k big-mod point
1685 &aux (modulus big-mod) (main-var (p-var u)) tem fi+1 gi+1 v f0 g0 varl w aw bw)
1686 (setq v (psublis (subs-translate-sublis point) 1 u))
1687 (setq varl (delete (car u) (list-variables u) :test #'equal))
1688 (setq f0 fi)
1689 (setq g0 gi)
1690 (loop for i from 1 to up-to-k
1692 (setq w (pdifference (afp-times fi gi) u))
1693 (setq w (afp-truncate-powers w varl i))
1694 (mshow w)
1695 (cond ((pzerop w) 'nothing-to-do)
1697 (cond ((or (numberp w) (not (eql (p-var w) main-var)))
1698 (setq aw (afp-times w (first (setq tem (express-x^i f0 g0 0)))))
1699 (setq aw (afp-times w (second tem))))
1701 (loop for (deg cof) on (cdr w) by #'cddr
1702 initially (setq aw 0 bw 0)
1704 (setq aw (afp-plus aw (afp-times (first (setq tem (express-x^i f0 g0 deg))) cof)))
1705 (setq bw (afp-plus bw (afp-times (second tem) cof))))
1707 (setq fi+1 (pdifference fi bw))
1708 (setq gi+1 (pdifference gi aw))
1710 (setq fi fi+1 gi gi+1)
1711 (mshow aw bw fi gi)))))
1712 finally
1713 (show (pdifference v (ptimes fi gi)))
1714 (return (list fi gi))))
1716 (defun afp-truncate-powers (pol varl deg)
1717 (setq varl (sort varl 'pointergp))
1718 ( afp-truncate-powers1 pol varl deg))
1720 (defun afp-truncate-powers1 (pol varl above-deg &aux new-cof tem)
1721 (cond ((< above-deg 0) 0)
1722 ((numberp pol) pol)
1723 ((null varl) pol)
1724 ((member (p-var pol) varl :test #'eq)
1725 (psimp (p-var pol)
1726 (loop for (exp cof) on (cdr pol) by #'cddr
1727 do (setq tem (- above-deg exp))
1728 when (< tem 0)
1729 nconc nil
1730 else
1731 do (setq new-cof (afp-truncate-powers1 cof (cdr varl) tem))
1732 and when (not(pzerop new-cof))
1733 nconc (list exp new-cof))))
1734 (t(psimp (p-var pol)
1735 (loop for (exp cof) on (cdr pol) by #'cddr
1736 when(not (pzerop (setq new-cof (afp-truncate-powers1 cof varl above-deg))))
1737 nconc (list exp new-cof))))))
1741 (defun normalize-factor-list (factor-list &aux tot-deg)
1742 "checks factor-list and eliminates repeats. All integer factors are grouped at the beginning if any"
1743 (let (numerical-factor(facts (collect-number-factors factor-list)))
1744 (cond ((numberp (car facts))
1745 (setq numerical-factor (subseq facts 0 2))
1746 (setq facts (cddr facts))))
1747 (nconc numerical-factor
1748 (loop for (pol deg) on facts by #'cddr
1749 for rest-facts on facts by #'cddr
1750 do (show facts deg)
1751 when deg
1752 do (setq tot-deg
1753 (+ deg
1754 (loop for v on (cddr rest-facts) by #'cddr
1755 when (and (second v) (equal pol (car v)))
1756 summing (second v)
1757 and do (setf (second v) nil))))
1759 collecting pol and collecting tot-deg))))
1761 ;; (defmacro while (test &body body)
1762 ;; `(loop (cond ((null ,test) (return)))
1763 ;; ,@ body))
1765 (defun find-factor-list-given-irreducible-factors (pol fact-list &aux deg divisor answ final-answ)
1766 (while (setq divisor (car fact-list))
1767 (setq deg 1)
1768 (while (setq answ (test-divide pol divisor))
1769 (setq pol answ)
1770 (incf deg))
1771 (setq final-answ (cons deg final-answ))
1772 (setq final-answ (cons pol final-answ)))
1773 (unless (equal final-answ 1)
1774 (fsignal "bad factorization"))
1775 final-answ)
1777 ;(defun afp-multi-factor (pol)
1778 ; (let ((content (afp-content pol)))
1779 ; (cond (content (normalize-factorlist
1780 ; (append (afp-multi-factor content)
1781 ; (afp-multi-factor (afp-quotient pol content )))))
1782 ; (t (afp-)))))
1784 (defun try-multi-factor0 (pol &aux facs fac deg)
1785 "input may be non square free"
1786 (setq facs (afp-square-free-factorization pol))
1787 (prog (result)
1788 next-factor
1789 (setq fac (car facs) deg (second facs) facs (cddr facs))
1790 (prog
1791 ((newfacs (try-multi-factor1 fac)))
1792 next-factor
1793 (push (* (second newfacs) deg) result)
1794 (push (car newfacs) result)
1795 (setq newfacs (cddr newfacs))
1796 (and newfacs (go next-factor)))
1797 (and facs (go next-factor))
1798 (return result)))
1801 (defun afp-degvector (pol vars &aux (result (make-list (length vars))))
1802 (do ((v vars (cdr v))
1803 (w result (cdr result)))
1804 ((null v) result)
1805 (setf (car w) (pdegree pol (car v)))))
1807 (defun afp-smallest-var (degvector list-variables &aux (best (expt 2 20)) best-variable )
1808 (do ((v degvector (cdr v))
1809 (w list-variables (cdr w)))
1810 ((null v) best-variable)
1811 (cond ((< (car v) best)
1812 (setq best-variable (car w))))))
1814 ;;description of eez algorithm with enhancements:
1816 ;1) make U squarefree and content 1
1817 ;2) make main variable be smallest degree variable
1818 ;3) factor leading coefficient into F1,f2,..fk,fk+1 (fk+1 = content)
1819 ;4) find a point in x2,...,xn space such that
1820 ;there exist p1,..,pk+1, pi|fj iff i = j
1821 ;and
1822 ;such that we have the right number of factors of U mod (point, B) (B big bound).
1823 ;5) Match up pi, and the univariate factors.
1826 ;(defun try-multi-factor1 (pol)
1827 ; "Pol is square free multivariate"
1828 ; (let* ((list-variables (list-variables pol))
1829 ; (degvector (afp-degvector pol list-variables))
1830 ; (best-variable (afp-smallest-var degvector list-variables))
1831 ; (leading-cof (pcoeff pol best-variable))
1832 ; (point (delq best-variable (copy-list list-variables))))
1833 ; (do ((v point (cdr v)))
1834 ; (null v)
1835 ; (setf (car v (cons (car v) (nth (random 5) *small-primes*)))))
1836 ; (let* ((lead-cof-at-point (psublis point 1 leading-cof)))
1837 ; (cond ((eql 0