1 ;;; -*- Package: MAXIMA; Base: 10.; Syntax: Common-lisp -*-
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4 ;;; Copyright (c) 1984 by William Schelter,University of Texas ;;;;;
5 ;;; All rights reserved ;;;;;
6 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11 (:compile-toplevel
:load-toplevel
:execute
)
13 (defmacro p-cof
(f) ;leading coefficient of f
16 (defmacro p-next-term
(f)
22 (defmacro term-cof
(terms)
25 (defmacro term-deg
(terms)
28 ;;(make-poly var x)==> (list x 1 1)
30 (defun make-polynomial (&key var terms
)
33 (defun afc-quotient (f g
)
36 (defun fsignal (&rest 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
)))
46 (set-tellrats ,list-of-monic-polynomials
)
48 (undo-tellrats ,old-tellrats
))))
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
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"))
77 (loop for
(,deg
,cof
) on
(cdr ,f
) by
#'cddr
79 do
(setq ,tem
(,operation-function
,cof
,g
))
80 when
(not (pzerop ,tem
))
81 nconc
(list , (cond (deg-shift-result `(+ ,deg
,deg-shift-result
))
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"))
91 `(loop for
(,deg
,cof
) on
,terms-f by
#'cddr
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
))
99 (defmacro quotient-not-exact
()
100 `(cond ((and (boundp '*testing
*)
102 (throw 'quotient-not-exact t
))
103 (t (fsignal 'quotient-not-exact
))))
106 (DEFUN afp-CQUOTIENT
(A B
)
107 (declare (special *testing
*))
110 (let ((quot (quotient a b
)))
111 (cond ((eql (* quot b
) a
)
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."
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
)
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
))
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
))))
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
)))))
173 (defmacro afp-main-plus-non-main
(constant f-main
)
174 "Adds a polynomial CONSTANT to a polynomial whose main variable is higher than
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
))
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
)
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
)
224 (2 `(list (car ,l
) (second ,l
)))
225 (t `(subseq ,l
0 ,n
))))
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
)
238 `(cond ((pzerop ,cof
) ,terms
)
239 (t (cons ,deg
(cons ,cof
,terms
)))))
242 (cond ((pzerop .cof.
) ,terms
)
243 (t (cons ,deg
(cons .cof.
,terms
))))))))
245 (defun afp-difference (f g
)
247 (cond ((numberp g
)(cdifference f g
))
248 (t (psimp (p-var g
) (afp-terms-constant-main-differ f
(cdr 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
256 (t(psimp (p-var g
) (afp-terms-main-constant-differ
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
)
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
)))))
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
*))
297 (t (quotient-not-exact))))
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
))
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
)))
308 collecting deg-dif into q
309 collecting
(setq quot
(afp-quotient (p-cof f
) (p-cof g
)))
311 do
(setq minus-quot
(pminus quot
))
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
)))
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."
345 (apply #'values
(append '(1) (multiple-value-list (afc-remainder f g
)))))
349 ((pointergp (p-var f
) (p-var g
))
351 ((eq (p-var f
) (p-var g
))
352 (loop with quot with deg-dif with main-var
= (p-var f
)
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
)))
362 collecting deg-dif into q
363 collecting
(setq quot
(afp-quotient (p-cof remainder
) (p-cof g
)))
366 (setq remainder
(pplus
372 while
(and (not (numberp remainder
))
373 (eql (p-var remainder
) main-var
))
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
))))
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
)))))
386 (defun gen-pointergp (f g
)
387 (cond ((numberp g
) t
)
389 (t (pointergp (p-var f
) (p-var g
)))))
391 (defun gen-degree (f)
392 (cond ((numberp f
) 0)
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
))))))
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. "
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
))
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
432 (assume-pointerg-or-equal-p f g
)
433 (cond ((numberp f
)(gcd f g
))
435 (afp-gcd (afp-content f
) g
))
436 ; (loop for (deg cof) on (p-terms f) by #'cddr
438 ; do (setq gcd (afp-gcd cof gcd))
439 ; finally (return gcd)))
440 ((eq (p-var f
) (p-var g
))
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
)
447 do
(multiple-value-setq (unused r
) (afp-pseudo-quotient u v
))
449 do
(return (ptimes d v
))
450 when
(gen-pointergp f r
)
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
))
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
))
483 do
(return (ptimes d
(principal-part v
)))
484 when
(gen-pointergp f r
)
487 (setq v
(afp-quotient r
(ptimes gg
(pexpt h delta
))))
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))))
494 (t (ptimes g^delta h
))))))
495 (afp-try-make-monic answ
))))
498 (defun one-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
508 do
(setq numer
(one-ptimes numer fact
))
511 do
(setq numer
(one-ptimes numer
(pexpt fact deg
)))
514 do
(setq denom
(one-ptimes denom fact
))
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
))))))
527 ;(defun afp-sqfr (f &aux deriv d)
528 ; (cond ((numberp f) f)
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)
538 ; (loop for (deg cof) on (cdr f) by #'cddr
539 ; collecting (quotient deg modulus)
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)))
560 (multiple-value-bind (d qf qg
)
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
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
)
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
593 (afp-square-free-with-modulus 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
))))
607 (fsignal 'how-did-this-happen
))
610 with vi
= v1 with wi
= w1 with videriv with vi
+1 with ui with wi
+1
611 with main-var
= (p-var u
)
613 (setq videriv
(pderivative vi main-var
))
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
622 ; (show vi wi ui vi+1 wi+1)
623 when
(not (eql ui
1))
624 nconc
(list ui i
) into factor-list
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
633 do
(setq answ
(ptimes answ
(pexpt (p-cof pol
) deg
)))
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
639 when
(oddp deg1
) do
(setf (nth i some-factors
)
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
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
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"
678 (t (afp-pctimes g f
))))
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
696 ; (plain-term-operation terms-g (term-cof terms-f) afp-times (term-deg terms-f)))
698 ; do (setq terms-f (cddr terms-f)))
699 ; (cond ((null one-product) nil)
701 ; (loop for (deg-f cof-f) on (cddr terms-f) by 'cddr
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
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)))))
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
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))))
736 ; (t (setf (cddr prev) (cons new-deg (cons to-add vvv)))
737 ; (setq prev (cddr prev))
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
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
)
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
))))))
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
778 do
(setf (third v
) (remove-zero-coefficients (third v
)))
779 when
(pzerop (third v
))
780 do
(setf (cdr v
) (cdddr v
))
783 finally
(return (cond ((null (cdr poly
)) 0)
784 ((zerop (second poly
))(third 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
)
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))))
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
)
837 (loop for v in
(cdr sum
)
839 collecting
1 into cof
841 when
(and (listp v
) (member u
(cdr v
) :test
'equal
))
843 (cond ((eql (length v
) 3)
844 (loop for vv in
(cdr v
)
845 when
(not (equal vv u
))
848 when
(not (equal vv u
))
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
)
866 (setq main-var
(p-var polynomial
))
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
))
874 with repl
= (cdr (car alist
))
875 with answ
= (afp-pctimes
877 (cdr alist
) (p-cof polynomial
))
878 (cexpt repl
(p-deg polynomial
)))
882 (constant-psublis1 (cdr alist
) cof
))
883 (t (afp-pctimes (constant-psublis1
885 (cexpt repl deg
))))))
886 finally
(return-from sue answ
)))
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).
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
)
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))
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
))
941 (t (gcd n
(mod m n
)))))
944 (defun bin-gcd (u v
&aux
(k 0)u2 v2 t2 tt
)
946 do
(setq u2
(ash u -
1))
947 when
(not (eql (ash u2
1) u
))
949 do
(setq v2
(ash v -
1))
950 when
(not (eql (ash v2
1) v
))
952 do
(setq u u2 v v2 k
(1+ k
)))
955 (cond ((oddp u
) (setq tt
(- v
)))
956 (t (setq tt
(ash u -
1))))
958 (loop do
(setq t2
(ash tt -
1))
959 when
(eql (ash t2
1) tt
)
961 else do
(return nil
))
962 (cond ((> tt
0) (setq u tt
))
965 (cond ((zerop tt
)(return (ash u k
)))
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
)
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
)
980 (vector-push poly row
))
982 (loop for u in
(cdr poly
) do
983 (vector-push u 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)
1005 ;; (iassert (equal (tim (afp-square f)) (remove-zero-coefficients (tim (pexpt f 2 ))))))
1014 ;; (iassert (equal (tim (afp-square f)) (tim (pexpt f 2)))))))
1016 ;; (defun test-square (f &key empty)
1018 ;; (iassert (equal (tim (afp-square f)) (remove-zero-coefficients (tim (ptimes f f))))))
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
)
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
))
1046 (setq p-terms
(cddr p-terms
))
1047 (setq p2-terms
(cddr p2-terms
))
1049 (t (go second-leading-square
))))
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
))))
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
)))
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
)))
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
)))))
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
)
1093 (iassert (equal (setq ansa
(tim (apply ',f1 rest-args
)))
1094 (setq ansb
(remove-zero-coefficients (tim (apply ',f2 rest-args
))))))))
1096 (apply ',f1 rest-args
)
1099 (apply ',f2 rest-args
)
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
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"
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
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
))
1148 with
2^i-power-poly
= poly
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)
1165 (list (* (p-deg poly
) exponent
)
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
)
1179 with pol
= (afp-expt (list (p-var u
) 1 1) p
)
1180 with pow
= 1 with belo
= (1- (p-deg u
))
1185 else do
(setq pow
(afp-times pol pow
)))))
1186 (loop for i below
(max 5 (length 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
)
1197 (push-poly-number-deg-cof rows i
0 vv
)
1198 (push-poly-number-deg-cof rows i i -
1)
1201 (loop for
(deg cof
) on
(p-terms vv
) by
#'p-next-term
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
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
))
1220 (defun berlekamp-polynomial-solutions (sp polynomial
&aux sp-sols
)
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
1234 (t (setq b-polys
(berlekamp-polynomial-solutions
1235 reduced-sparse-matrix u
))
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
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
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))
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
)))
1276 (setq pow
(pdifference (afp-expt v half-p
) 1)))
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
))))
1284 collecting
(afp-quotient w tem
)
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)
1303 (cond ((numberp (p-cof poly
))
1304 (afp-pctimes poly
(crecip (p-cof 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
))))
1317 do
(setq ans
(ptimes ans v
))
1318 finally
(show ans
) (iassert (equal (afp-mod pol
) ans
)))
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
* )
1337 (loop for
(pol deg
) on facts by
#'cddr
1341 (loop for fa in
(funcall factor-function pol
)
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
)))
1350 (t (fsignal 'not-yet-without-modulus
))))
1351 (cond (*sort-factors
* (sort-grouped-list answ
2 'alphagreatp
))
1354 (defun afp-mod (pol)
1355 (afp-pctimes pol
1))
1357 (defun get-factors (u use-for-gcd p
&aux tem
)
1359 (loop for w in use-for-gcd
1362 when
(not (numberp (setq tem
(afp-gcd (pplus w i
) u
))))
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"
1373 (loop do
(cond ((numberp v
) (return answ
))
1374 ((> (* 2 (1+ d
)) (p-deg v
))(return (cons v answ
))))
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
) )))
1391 (defun tel (u n p
&aux
(modulus p
))
1392 (check-arg p
(oddp p
) "odd")
1393 (iassert (eql (p-deg u
)
1395 summing
(p-deg v
) )))
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
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
))
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
) )))
1432 (defun generate-t-for-one-degree-factors (u deg p i
&aux tem
)
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
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
))
1444 (loop for
(pol pow
) on facts by
#'cddr
1446 (setq fact1
(afp-distinct-degree-factor pol prime
))
1448 (loop for ww in fact1
1449 collecting ww collecting pow
))
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
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
)
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
)))
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
) )
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
)))
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
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
)))))
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
))
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
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
))))))
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")
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
))
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"
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
)
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
))
1622 do
(setq factors
(delete vv factors
:count
1 :test
#'equal
)))
1623 (go look-for-factors
)))
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)))))
1631 ((loop for v in
(cdr lis
)
1632 when
(zerop (mod i v
))
1638 (defun test-integer-factor (pol &aux facts
)
1639 (setq facts
(integer-univariate-factor pol
))
1640 (iassert (equal pol
(apply 'exponent-product 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
))
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
))
1670 ;;(iassert (equal mon (afp-plus (afp-times f a) (afp-times g 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
))
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
))
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
)))))
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)
1724 ((member (p-var pol
) varl
:test
#'eq
)
1726 (loop for
(exp cof
) on
(cdr pol
) by
#'cddr
1727 do
(setq tem
(- above-deg exp
))
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
1754 (loop for v on
(cddr rest-facts
) by
#'cddr
1755 when
(and (second v
) (equal pol
(car 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)))
1765 (defun find-factor-list-given-irreducible-factors (pol fact-list
&aux deg divisor answ final-answ
)
1766 (while (setq divisor
(car fact-list
))
1768 (while (setq answ
(test-divide pol divisor
))
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"))
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 )))))
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
))
1789 (setq fac
(car facs
) deg
(second facs
) facs
(cddr facs
))
1791 ((newfacs (try-multi-factor1 fac
)))
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
))
1801 (defun afp-degvector (pol vars
&aux
(result (make-list (length vars
))))
1802 (do ((v vars
(cdr v
))
1803 (w result
(cdr 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
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)))
1835 ; (setf (car v (cons (car v) (nth (random 5) *small-primes*)))))
1836 ; (let* ((lead-cof-at-point (psublis point 1 leading-cof)))