]> code.delx.au - gnu-emacs/blob - lisp/calc/calc-poly.el
bd9a9f9ce7729a254485861d87b4246d9005b4fa
[gnu-emacs] / lisp / calc / calc-poly.el
1 ;;; calc-poly.el --- polynomial functions for Calc
2
3 ;; Copyright (C) 1990-1993, 2001-2015 Free Software Foundation, Inc.
4
5 ;; Author: David Gillespie <daveg@synaptics.com>
6
7 ;; This file is part of GNU Emacs.
8
9 ;; GNU Emacs is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
21
22 ;;; Commentary:
23
24 ;;; Code:
25
26 ;; This file is autoloaded from calc-ext.el.
27
28 (require 'calc-ext)
29 (require 'calc-macs)
30
31 (defun calcFunc-pcont (expr &optional var)
32 (cond ((Math-primp expr)
33 (cond ((Math-zerop expr) 1)
34 ((Math-messy-integerp expr) (math-trunc expr))
35 ((Math-objectp expr) expr)
36 ((or (equal expr var) (not var)) 1)
37 (t expr)))
38 ((eq (car expr) '*)
39 (math-mul (calcFunc-pcont (nth 1 expr) var)
40 (calcFunc-pcont (nth 2 expr) var)))
41 ((eq (car expr) '/)
42 (math-div (calcFunc-pcont (nth 1 expr) var)
43 (calcFunc-pcont (nth 2 expr) var)))
44 ((and (eq (car expr) '^) (Math-natnump (nth 2 expr)))
45 (math-pow (calcFunc-pcont (nth 1 expr) var) (nth 2 expr)))
46 ((memq (car expr) '(neg polar))
47 (calcFunc-pcont (nth 1 expr) var))
48 ((consp var)
49 (let ((p (math-is-polynomial expr var)))
50 (if p
51 (let ((lead (nth (1- (length p)) p))
52 (cont (math-poly-gcd-list p)))
53 (if (math-guess-if-neg lead)
54 (math-neg cont)
55 cont))
56 1)))
57 ((memq (car expr) '(+ - cplx sdev))
58 (let ((cont (calcFunc-pcont (nth 1 expr) var)))
59 (if (eq cont 1)
60 1
61 (let ((c2 (calcFunc-pcont (nth 2 expr) var)))
62 (if (and (math-negp cont)
63 (if (eq (car expr) '-) (math-posp c2) (math-negp c2)))
64 (math-neg (math-poly-gcd cont c2))
65 (math-poly-gcd cont c2))))))
66 (var expr)
67 (t 1)))
68
69 (defun calcFunc-pprim (expr &optional var)
70 (let ((cont (calcFunc-pcont expr var)))
71 (if (math-equal-int cont 1)
72 expr
73 (math-poly-div-exact expr cont var))))
74
75 (defun math-div-poly-const (expr c)
76 (cond ((memq (car-safe expr) '(+ -))
77 (list (car expr)
78 (math-div-poly-const (nth 1 expr) c)
79 (math-div-poly-const (nth 2 expr) c)))
80 (t (math-div expr c))))
81
82 (defun calcFunc-pdeg (expr &optional var)
83 (if (Math-zerop expr)
84 '(neg (var inf var-inf))
85 (if var
86 (or (math-polynomial-p expr var)
87 (math-reject-arg expr "Expected a polynomial"))
88 (math-poly-degree expr))))
89
90 (defun math-poly-degree (expr)
91 (cond ((Math-primp expr)
92 (if (eq (car-safe expr) 'var) 1 0))
93 ((eq (car expr) 'neg)
94 (math-poly-degree (nth 1 expr)))
95 ((eq (car expr) '*)
96 (+ (math-poly-degree (nth 1 expr))
97 (math-poly-degree (nth 2 expr))))
98 ((eq (car expr) '/)
99 (- (math-poly-degree (nth 1 expr))
100 (math-poly-degree (nth 2 expr))))
101 ((and (eq (car expr) '^) (natnump (nth 2 expr)))
102 (* (math-poly-degree (nth 1 expr)) (nth 2 expr)))
103 ((memq (car expr) '(+ -))
104 (max (math-poly-degree (nth 1 expr))
105 (math-poly-degree (nth 2 expr))))
106 (t 1)))
107
108 (defun calcFunc-plead (expr var)
109 (cond ((eq (car-safe expr) '*)
110 (math-mul (calcFunc-plead (nth 1 expr) var)
111 (calcFunc-plead (nth 2 expr) var)))
112 ((eq (car-safe expr) '/)
113 (math-div (calcFunc-plead (nth 1 expr) var)
114 (calcFunc-plead (nth 2 expr) var)))
115 ((and (eq (car-safe expr) '^) (math-natnump (nth 2 expr)))
116 (math-pow (calcFunc-plead (nth 1 expr) var) (nth 2 expr)))
117 ((Math-primp expr)
118 (if (equal expr var)
119 1
120 expr))
121 (t
122 (let ((p (math-is-polynomial expr var)))
123 (if (cdr p)
124 (nth (1- (length p)) p)
125 1)))))
126
127
128
129
130
131 ;;; Polynomial quotient, remainder, and GCD.
132 ;;; Originally by Ove Ewerlid (ewerlid@mizar.DoCS.UU.SE).
133 ;;; Modifications and simplifications by daveg.
134
135 (defvar math-poly-modulus 1)
136
137 ;;; Return gcd of two polynomials
138 (defun calcFunc-pgcd (pn pd)
139 (if (math-any-floats pn)
140 (math-reject-arg pn "Coefficients must be rational"))
141 (if (math-any-floats pd)
142 (math-reject-arg pd "Coefficients must be rational"))
143 (let ((calc-prefer-frac t)
144 (math-poly-modulus (math-poly-modulus pn pd)))
145 (math-poly-gcd pn pd)))
146
147 ;;; Return only quotient to top of stack (nil if zero)
148
149 ;; calc-poly-div-remainder is a local variable for
150 ;; calc-poly-div (in calc-alg.el), but is used by
151 ;; calcFunc-pdiv, which is called by calc-poly-div.
152 (defvar calc-poly-div-remainder)
153
154 (defun calcFunc-pdiv (pn pd &optional base)
155 (let* ((calc-prefer-frac t)
156 (math-poly-modulus (math-poly-modulus pn pd))
157 (res (math-poly-div pn pd base)))
158 (setq calc-poly-div-remainder (cdr res))
159 (car res)))
160
161 ;;; Return only remainder to top of stack
162 (defun calcFunc-prem (pn pd &optional base)
163 (let ((calc-prefer-frac t)
164 (math-poly-modulus (math-poly-modulus pn pd)))
165 (cdr (math-poly-div pn pd base))))
166
167 (defun calcFunc-pdivrem (pn pd &optional base)
168 (let* ((calc-prefer-frac t)
169 (math-poly-modulus (math-poly-modulus pn pd))
170 (res (math-poly-div pn pd base)))
171 (list 'vec (car res) (cdr res))))
172
173 (defun calcFunc-pdivide (pn pd &optional base)
174 (let* ((calc-prefer-frac t)
175 (math-poly-modulus (math-poly-modulus pn pd))
176 (res (math-poly-div pn pd base)))
177 (math-add (car res) (math-div (cdr res) pd))))
178
179
180 ;;; Multiply two terms, expanding out products of sums.
181 (defun math-mul-thru (lhs rhs)
182 (if (memq (car-safe lhs) '(+ -))
183 (list (car lhs)
184 (math-mul-thru (nth 1 lhs) rhs)
185 (math-mul-thru (nth 2 lhs) rhs))
186 (if (memq (car-safe rhs) '(+ -))
187 (list (car rhs)
188 (math-mul-thru lhs (nth 1 rhs))
189 (math-mul-thru lhs (nth 2 rhs)))
190 (math-mul lhs rhs))))
191
192 (defun math-div-thru (num den)
193 (if (memq (car-safe num) '(+ -))
194 (list (car num)
195 (math-div-thru (nth 1 num) den)
196 (math-div-thru (nth 2 num) den))
197 (math-div num den)))
198
199
200 ;;; Sort the terms of a sum into canonical order.
201 (defun math-sort-terms (expr)
202 (if (memq (car-safe expr) '(+ -))
203 (math-list-to-sum
204 (sort (math-sum-to-list expr)
205 (function (lambda (a b) (math-beforep (car a) (car b))))))
206 expr))
207
208 (defun math-list-to-sum (lst)
209 (if (cdr lst)
210 (list (if (cdr (car lst)) '- '+)
211 (math-list-to-sum (cdr lst))
212 (car (car lst)))
213 (if (cdr (car lst))
214 (math-neg (car (car lst)))
215 (car (car lst)))))
216
217 (defun math-sum-to-list (tree &optional neg)
218 (cond ((eq (car-safe tree) '+)
219 (nconc (math-sum-to-list (nth 1 tree) neg)
220 (math-sum-to-list (nth 2 tree) neg)))
221 ((eq (car-safe tree) '-)
222 (nconc (math-sum-to-list (nth 1 tree) neg)
223 (math-sum-to-list (nth 2 tree) (not neg))))
224 (t (list (cons tree neg)))))
225
226 ;;; Check if the polynomial coefficients are modulo forms.
227 (defun math-poly-modulus (expr &optional expr2)
228 (or (math-poly-modulus-rec expr)
229 (and expr2 (math-poly-modulus-rec expr2))
230 1))
231
232 (defun math-poly-modulus-rec (expr)
233 (if (and (eq (car-safe expr) 'mod) (Math-natnump (nth 2 expr)))
234 (list 'mod 1 (nth 2 expr))
235 (and (memq (car-safe expr) '(+ - * /))
236 (or (math-poly-modulus-rec (nth 1 expr))
237 (math-poly-modulus-rec (nth 2 expr))))))
238
239
240 ;;; Divide two polynomials. Return (quotient . remainder).
241 (defvar math-poly-div-base nil)
242 (defun math-poly-div (u v &optional math-poly-div-base)
243 (if math-poly-div-base
244 (math-do-poly-div u v)
245 (math-do-poly-div (calcFunc-expand u) (calcFunc-expand v))))
246
247 (defun math-poly-div-exact (u v &optional base)
248 (let ((res (math-poly-div u v base)))
249 (if (eq (cdr res) 0)
250 (car res)
251 (math-reject-arg (list 'vec u v) "Argument is not a polynomial"))))
252
253 (defun math-do-poly-div (u v)
254 (cond ((math-constp u)
255 (if (math-constp v)
256 (cons (math-div u v) 0)
257 (cons 0 u)))
258 ((math-constp v)
259 (cons (if (eq v 1)
260 u
261 (if (memq (car-safe u) '(+ -))
262 (math-add-or-sub (math-poly-div-exact (nth 1 u) v)
263 (math-poly-div-exact (nth 2 u) v)
264 nil (eq (car u) '-))
265 (math-div u v)))
266 0))
267 ((Math-equal u v)
268 (cons math-poly-modulus 0))
269 ((and (math-atomic-factorp u) (math-atomic-factorp v))
270 (cons (math-simplify (math-div u v)) 0))
271 (t
272 (let ((base (or math-poly-div-base
273 (math-poly-div-base u v)))
274 vp up res)
275 (if (or (null base)
276 (null (setq vp (math-is-polynomial v base nil 'gen))))
277 (cons 0 u)
278 (setq up (math-is-polynomial u base nil 'gen)
279 res (math-poly-div-coefs up vp))
280 (cons (math-build-polynomial-expr (car res) base)
281 (math-build-polynomial-expr (cdr res) base)))))))
282
283 (defun math-poly-div-rec (u v)
284 (cond ((math-constp u)
285 (math-div u v))
286 ((math-constp v)
287 (if (eq v 1)
288 u
289 (if (memq (car-safe u) '(+ -))
290 (math-add-or-sub (math-poly-div-rec (nth 1 u) v)
291 (math-poly-div-rec (nth 2 u) v)
292 nil (eq (car u) '-))
293 (math-div u v))))
294 ((Math-equal u v) math-poly-modulus)
295 ((and (math-atomic-factorp u) (math-atomic-factorp v))
296 (math-simplify (math-div u v)))
297 (math-poly-div-base
298 (math-div u v))
299 (t
300 (let ((base (math-poly-div-base u v))
301 vp up res)
302 (if (or (null base)
303 (null (setq vp (math-is-polynomial v base nil 'gen))))
304 (math-div u v)
305 (setq up (math-is-polynomial u base nil 'gen)
306 res (math-poly-div-coefs up vp))
307 (math-add (math-build-polynomial-expr (car res) base)
308 (math-div (math-build-polynomial-expr (cdr res) base)
309 v)))))))
310
311 ;;; Divide two polynomials in coefficient-list form. Return (quot . rem).
312 (defun math-poly-div-coefs (u v)
313 (cond ((null v) (math-reject-arg nil "Division by zero"))
314 ((< (length u) (length v)) (cons nil u))
315 ((cdr u)
316 (let ((q nil)
317 (urev (reverse u))
318 (vrev (reverse v)))
319 (while
320 (let ((qk (math-poly-div-rec (math-simplify (car urev))
321 (car vrev)))
322 (up urev)
323 (vp vrev))
324 (if (or q (not (math-zerop qk)))
325 (setq q (cons qk q)))
326 (while (setq up (cdr up) vp (cdr vp))
327 (setcar up (math-sub (car up) (math-mul-thru qk (car vp)))))
328 (setq urev (cdr urev))
329 up))
330 (while (and urev (Math-zerop (car urev)))
331 (setq urev (cdr urev)))
332 (cons q (nreverse (mapcar 'math-simplify urev)))))
333 (t
334 (cons (list (math-poly-div-rec (car u) (car v)))
335 nil))))
336
337 ;;; Perform a pseudo-division of polynomials. (See Knuth section 4.6.1.)
338 ;;; This returns only the remainder from the pseudo-division.
339 (defun math-poly-pseudo-div (u v)
340 (cond ((null v) nil)
341 ((< (length u) (length v)) u)
342 ((or (cdr u) (cdr v))
343 (let ((urev (reverse u))
344 (vrev (reverse v))
345 up)
346 (while
347 (let ((vp vrev))
348 (setq up urev)
349 (while (setq up (cdr up) vp (cdr vp))
350 (setcar up (math-sub (math-mul-thru (car vrev) (car up))
351 (math-mul-thru (car urev) (car vp)))))
352 (setq urev (cdr urev))
353 up)
354 (while up
355 (setcar up (math-mul-thru (car vrev) (car up)))
356 (setq up (cdr up))))
357 (while (and urev (Math-zerop (car urev)))
358 (setq urev (cdr urev)))
359 (nreverse (mapcar 'math-simplify urev))))
360 (t nil)))
361
362 ;;; Compute the GCD of two multivariate polynomials.
363 (defun math-poly-gcd (u v)
364 (cond ((Math-equal u v) u)
365 ((math-constp u)
366 (if (Math-zerop u)
367 v
368 (calcFunc-gcd u (calcFunc-pcont v))))
369 ((math-constp v)
370 (if (Math-zerop v)
371 v
372 (calcFunc-gcd v (calcFunc-pcont u))))
373 (t
374 (let ((base (math-poly-gcd-base u v)))
375 (if base
376 (math-simplify
377 (calcFunc-expand
378 (math-build-polynomial-expr
379 (math-poly-gcd-coefs (math-is-polynomial u base nil 'gen)
380 (math-is-polynomial v base nil 'gen))
381 base)))
382 (calcFunc-gcd (calcFunc-pcont u) (calcFunc-pcont u)))))))
383
384 (defun math-poly-div-list (lst a)
385 (if (eq a 1)
386 lst
387 (if (eq a -1)
388 (math-mul-list lst a)
389 (mapcar (function (lambda (x) (math-poly-div-exact x a))) lst))))
390
391 (defun math-mul-list (lst a)
392 (if (eq a 1)
393 lst
394 (if (eq a -1)
395 (mapcar 'math-neg lst)
396 (and (not (eq a 0))
397 (mapcar (function (lambda (x) (math-mul x a))) lst)))))
398
399 ;;; Run GCD on all elements in a list.
400 (defun math-poly-gcd-list (lst)
401 (if (or (memq 1 lst) (memq -1 lst))
402 (math-poly-gcd-frac-list lst)
403 (let ((gcd (car lst)))
404 (while (and (setq lst (cdr lst)) (not (eq gcd 1)))
405 (or (eq (car lst) 0)
406 (setq gcd (math-poly-gcd gcd (car lst)))))
407 (if lst (setq lst (math-poly-gcd-frac-list lst)))
408 gcd)))
409
410 (defun math-poly-gcd-frac-list (lst)
411 (while (and lst (not (eq (car-safe (car lst)) 'frac)))
412 (setq lst (cdr lst)))
413 (if lst
414 (let ((denom (nth 2 (car lst))))
415 (while (setq lst (cdr lst))
416 (if (eq (car-safe (car lst)) 'frac)
417 (setq denom (calcFunc-lcm denom (nth 2 (car lst))))))
418 (list 'frac 1 denom))
419 1))
420
421 ;;; Compute the GCD of two univariate polynomial lists.
422 ;;; Knuth section 4.6.1, algorithm C.
423 (defun math-poly-gcd-coefs (u v)
424 (let ((d (math-poly-gcd (math-poly-gcd-list u)
425 (math-poly-gcd-list v)))
426 (g 1) (h 1) (z 0) hh r delta ghd)
427 (while (and u v (Math-zerop (car u)) (Math-zerop (car v)))
428 (setq u (cdr u) v (cdr v) z (1+ z)))
429 (or (eq d 1)
430 (setq u (math-poly-div-list u d)
431 v (math-poly-div-list v d)))
432 (while (progn
433 (setq delta (- (length u) (length v)))
434 (if (< delta 0)
435 (setq r u u v v r delta (- delta)))
436 (setq r (math-poly-pseudo-div u v))
437 (cdr r))
438 (setq u v
439 v (math-poly-div-list r (math-mul g (math-pow h delta)))
440 g (nth (1- (length u)) u)
441 h (if (<= delta 1)
442 (math-mul (math-pow g delta) (math-pow h (- 1 delta)))
443 (math-poly-div-exact (math-pow g delta)
444 (math-pow h (1- delta))))))
445 (setq v (if r
446 (list d)
447 (math-mul-list (math-poly-div-list v (math-poly-gcd-list v)) d)))
448 (if (math-guess-if-neg (nth (1- (length v)) v))
449 (setq v (math-mul-list v -1)))
450 (while (>= (setq z (1- z)) 0)
451 (setq v (cons 0 v)))
452 v))
453
454
455 ;;; Return true if is a factor containing no sums or quotients.
456 (defun math-atomic-factorp (expr)
457 (cond ((eq (car-safe expr) '*)
458 (and (math-atomic-factorp (nth 1 expr))
459 (math-atomic-factorp (nth 2 expr))))
460 ((memq (car-safe expr) '(+ - /))
461 nil)
462 ((memq (car-safe expr) '(^ neg))
463 (math-atomic-factorp (nth 1 expr)))
464 (t t)))
465
466 ;;; Find a suitable base for dividing a by b.
467 ;;; The base must exist in both expressions.
468 ;;; The degree in the numerator must be higher or equal than the
469 ;;; degree in the denominator.
470 ;;; If the above conditions are not met the quotient is just a remainder.
471 ;;; Return nil if this is the case.
472
473 (defun math-poly-div-base (a b)
474 (let (a-base b-base)
475 (and (setq a-base (math-total-polynomial-base a))
476 (setq b-base (math-total-polynomial-base b))
477 (catch 'return
478 (while a-base
479 (let ((maybe (assoc (car (car a-base)) b-base)))
480 (if maybe
481 (if (>= (nth 1 (car a-base)) (nth 1 maybe))
482 (throw 'return (car (car a-base))))))
483 (setq a-base (cdr a-base)))))))
484
485 ;;; Same as above but for gcd algorithm.
486 ;;; Here there is no requirement that degree(a) > degree(b).
487 ;;; Take the base that has the highest degree considering both a and b.
488 ;;; ("a^20+b^21+x^3+a+b", "a+b^2+x^5+a^22+b^10") --> (a 22)
489
490 (defun math-poly-gcd-base (a b)
491 (let (a-base b-base)
492 (and (setq a-base (math-total-polynomial-base a))
493 (setq b-base (math-total-polynomial-base b))
494 (catch 'return
495 (while (and a-base b-base)
496 (if (> (nth 1 (car a-base)) (nth 1 (car b-base)))
497 (if (assoc (car (car a-base)) b-base)
498 (throw 'return (car (car a-base)))
499 (setq a-base (cdr a-base)))
500 (if (assoc (car (car b-base)) a-base)
501 (throw 'return (car (car b-base)))
502 (setq b-base (cdr b-base)))))))))
503
504 ;;; Sort a list of polynomial bases.
505 (defun math-sort-poly-base-list (lst)
506 (sort lst (function (lambda (a b)
507 (or (> (nth 1 a) (nth 1 b))
508 (and (= (nth 1 a) (nth 1 b))
509 (math-beforep (car a) (car b))))))))
510
511 ;;; Given an expression find all variables that are polynomial bases.
512 ;;; Return list in the form '( (var1 degree1) (var2 degree2) ... ).
513
514 ;; The variable math-poly-base-total-base is local to
515 ;; math-total-polynomial-base, but is used by math-polynomial-p1,
516 ;; which is called by math-total-polynomial-base.
517 (defvar math-poly-base-total-base)
518
519 (defun math-total-polynomial-base (expr)
520 (let ((math-poly-base-total-base nil))
521 (math-polynomial-base expr 'math-polynomial-p1)
522 (math-sort-poly-base-list math-poly-base-total-base)))
523
524 ;; The variable math-poly-base-top-expr is local to math-polynomial-base
525 ;; in calc-alg.el, but is used by math-polynomial-p1 which is called
526 ;; by math-polynomial-base.
527 (defvar math-poly-base-top-expr)
528
529 (defun math-polynomial-p1 (subexpr)
530 (or (assoc subexpr math-poly-base-total-base)
531 (memq (car subexpr) '(+ - * / neg))
532 (and (eq (car subexpr) '^) (natnump (nth 2 subexpr)))
533 (let* ((math-poly-base-variable subexpr)
534 (exponent (math-polynomial-p math-poly-base-top-expr subexpr)))
535 (if exponent
536 (setq math-poly-base-total-base (cons (list subexpr exponent)
537 math-poly-base-total-base)))))
538 nil)
539
540 ;; The variable math-factored-vars is local to calcFunc-factors and
541 ;; calcFunc-factor, but is used by math-factor-expr and
542 ;; math-factor-expr-part, which are called (directly and indirectly) by
543 ;; calcFunc-factor and calcFunc-factors.
544 (defvar math-factored-vars)
545
546 ;; The variable math-fact-expr is local to calcFunc-factors,
547 ;; calcFunc-factor and math-factor-expr, but is used by math-factor-expr-try
548 ;; and math-factor-expr-part, which are called (directly and indirectly) by
549 ;; calcFunc-factor, calcFunc-factors and math-factor-expr.
550 (defvar math-fact-expr)
551
552 ;; The variable math-to-list is local to calcFunc-factors and
553 ;; calcFunc-factor, but is used by math-accum-factors, which is
554 ;; called (indirectly) by calcFunc-factors and calcFunc-factor.
555 (defvar math-to-list)
556
557 (defun calcFunc-factors (math-fact-expr &optional var)
558 (let ((math-factored-vars (if var t nil))
559 (math-to-list t)
560 (calc-prefer-frac t))
561 (or var
562 (setq var (math-polynomial-base math-fact-expr)))
563 (let ((res (math-factor-finish
564 (or (catch 'factor (math-factor-expr-try var))
565 math-fact-expr))))
566 (math-simplify (if (math-vectorp res)
567 res
568 (list 'vec (list 'vec res 1)))))))
569
570 (defun calcFunc-factor (math-fact-expr &optional var)
571 (let ((math-factored-vars nil)
572 (math-to-list nil)
573 (calc-prefer-frac t))
574 (math-simplify (math-factor-finish
575 (if var
576 (let ((math-factored-vars t))
577 (or (catch 'factor (math-factor-expr-try var)) math-fact-expr))
578 (math-factor-expr math-fact-expr))))))
579
580 (defun math-factor-finish (x)
581 (if (Math-primp x)
582 x
583 (if (eq (car x) 'calcFunc-Fac-Prot)
584 (math-factor-finish (nth 1 x))
585 (cons (car x) (mapcar 'math-factor-finish (cdr x))))))
586
587 (defun math-factor-protect (x)
588 (if (memq (car-safe x) '(+ -))
589 (list 'calcFunc-Fac-Prot x)
590 x))
591
592 (defun math-factor-expr (math-fact-expr)
593 (cond ((eq math-factored-vars t) math-fact-expr)
594 ((or (memq (car-safe math-fact-expr) '(* / ^ neg))
595 (assq (car-safe math-fact-expr) calc-tweak-eqn-table))
596 (cons (car math-fact-expr) (mapcar 'math-factor-expr (cdr math-fact-expr))))
597 ((memq (car-safe math-fact-expr) '(+ -))
598 (let* ((math-factored-vars math-factored-vars)
599 (y (catch 'factor (math-factor-expr-part math-fact-expr))))
600 (if y
601 (math-factor-expr y)
602 math-fact-expr)))
603 (t math-fact-expr)))
604
605 (defun math-factor-expr-part (x) ; uses "expr"
606 (if (memq (car-safe x) '(+ - * / ^ neg))
607 (while (setq x (cdr x))
608 (math-factor-expr-part (car x)))
609 (and (not (Math-objvecp x))
610 (not (assoc x math-factored-vars))
611 (> (math-factor-contains math-fact-expr x) 1)
612 (setq math-factored-vars (cons (list x) math-factored-vars))
613 (math-factor-expr-try x))))
614
615 ;; The variable math-fet-x is local to math-factor-expr-try, but is
616 ;; used by math-factor-poly-coefs, which is called by math-factor-expr-try.
617 (defvar math-fet-x)
618
619 (defun math-factor-expr-try (math-fet-x)
620 (if (eq (car-safe math-fact-expr) '*)
621 (let ((res1 (catch 'factor (let ((math-fact-expr (nth 1 math-fact-expr)))
622 (math-factor-expr-try math-fet-x))))
623 (res2 (catch 'factor (let ((math-fact-expr (nth 2 math-fact-expr)))
624 (math-factor-expr-try math-fet-x)))))
625 (and (or res1 res2)
626 (throw 'factor (math-accum-factors (or res1 (nth 1 math-fact-expr)) 1
627 (or res2 (nth 2 math-fact-expr))))))
628 (let* ((p (math-is-polynomial math-fact-expr math-fet-x 30 'gen))
629 (math-poly-modulus (math-poly-modulus math-fact-expr))
630 res)
631 (and (cdr p)
632 (setq res (math-factor-poly-coefs p))
633 (throw 'factor res)))))
634
635 (defun math-accum-factors (fac pow facs)
636 (if math-to-list
637 (if (math-vectorp fac)
638 (progn
639 (while (setq fac (cdr fac))
640 (setq facs (math-accum-factors (nth 1 (car fac))
641 (* pow (nth 2 (car fac)))
642 facs)))
643 facs)
644 (if (and (eq (car-safe fac) '^) (natnump (nth 2 fac)))
645 (setq pow (* pow (nth 2 fac))
646 fac (nth 1 fac)))
647 (if (eq fac 1)
648 facs
649 (or (math-vectorp facs)
650 (setq facs (if (eq facs 1) '(vec)
651 (list 'vec (list 'vec facs 1)))))
652 (let ((found facs))
653 (while (and (setq found (cdr found))
654 (not (equal fac (nth 1 (car found))))))
655 (if found
656 (progn
657 (setcar (cdr (cdr (car found))) (+ pow (nth 2 (car found))))
658 facs)
659 ;; Put constant term first.
660 (if (and (cdr facs) (Math-ratp (nth 1 (nth 1 facs))))
661 (cons 'vec (cons (nth 1 facs) (cons (list 'vec fac pow)
662 (cdr (cdr facs)))))
663 (cons 'vec (cons (list 'vec fac pow) (cdr facs))))))))
664 (math-mul (math-pow fac pow) (math-factor-protect facs))))
665
666 (defun math-factor-poly-coefs (p &optional square-free) ; uses "x"
667 (let (t1 t2 temp)
668 (cond ((not (cdr p))
669 (or (car p) 0))
670
671 ;; Strip off multiples of math-fet-x.
672 ((Math-zerop (car p))
673 (let ((z 0))
674 (while (and p (Math-zerop (car p)))
675 (setq z (1+ z) p (cdr p)))
676 (if (cdr p)
677 (setq p (math-factor-poly-coefs p square-free))
678 (setq p (math-sort-terms (math-factor-expr (car p)))))
679 (math-accum-factors math-fet-x z (math-factor-protect p))))
680
681 ;; Factor out content.
682 ((and (not square-free)
683 (not (eq 1 (setq t1 (math-mul (math-poly-gcd-list p)
684 (if (math-guess-if-neg
685 (nth (1- (length p)) p))
686 -1 1))))))
687 (math-accum-factors t1 1 (math-factor-poly-coefs
688 (math-poly-div-list p t1) 'cont)))
689
690 ;; Check if linear in math-fet-x.
691 ((not (cdr (cdr p)))
692 (math-sort-terms
693 (math-add (math-factor-protect
694 (math-sort-terms
695 (math-factor-expr (car p))))
696 (math-mul math-fet-x (math-factor-protect
697 (math-sort-terms
698 (math-factor-expr (nth 1 p))))))))
699
700 ;; If symbolic coefficients, use FactorRules.
701 ((let ((pp p))
702 (while (and pp (or (Math-ratp (car pp))
703 (and (eq (car (car pp)) 'mod)
704 (Math-integerp (nth 1 (car pp)))
705 (Math-integerp (nth 2 (car pp))))))
706 (setq pp (cdr pp)))
707 pp)
708 (let ((res (math-rewrite
709 (list 'calcFunc-thecoefs math-fet-x (cons 'vec p))
710 '(var FactorRules var-FactorRules))))
711 (or (and (eq (car-safe res) 'calcFunc-thefactors)
712 (= (length res) 3)
713 (math-vectorp (nth 2 res))
714 (let ((facs 1)
715 (vec (nth 2 res)))
716 (while (setq vec (cdr vec))
717 (setq facs (math-accum-factors (car vec) 1 facs)))
718 facs))
719 (math-build-polynomial-expr p math-fet-x))))
720
721 ;; Check if rational coefficients (i.e., not modulo a prime).
722 ((eq math-poly-modulus 1)
723
724 ;; Check if there are any squared terms, or a content not = 1.
725 (if (or (eq square-free t)
726 (equal (setq t1 (math-poly-gcd-coefs
727 p (setq t2 (math-poly-deriv-coefs p))))
728 '(1)))
729
730 ;; We now have a square-free polynomial with integer coefs.
731 ;; For now, we use a kludgy method that finds linear and
732 ;; quadratic terms using floating-point root-finding.
733 (if (setq t1 (let ((calc-symbolic-mode nil))
734 (math-poly-all-roots nil p t)))
735 (let ((roots (car t1))
736 (csign (if (math-negp (nth (1- (length p)) p)) -1 1))
737 (expr 1)
738 (unfac (nth 1 t1))
739 (scale (nth 2 t1)))
740 (while roots
741 (let ((coef0 (car (car roots)))
742 (coef1 (cdr (car roots))))
743 (setq expr (math-accum-factors
744 (if coef1
745 (let ((den (math-lcm-denoms
746 coef0 coef1)))
747 (setq scale (math-div scale den))
748 (math-add
749 (math-add
750 (math-mul den (math-pow math-fet-x 2))
751 (math-mul (math-mul coef1 den)
752 math-fet-x))
753 (math-mul coef0 den)))
754 (let ((den (math-lcm-denoms coef0)))
755 (setq scale (math-div scale den))
756 (math-add (math-mul den math-fet-x)
757 (math-mul coef0 den))))
758 1 expr)
759 roots (cdr roots))))
760 (setq expr (math-accum-factors
761 expr 1
762 (math-mul csign
763 (math-build-polynomial-expr
764 (math-mul-list (nth 1 t1) scale)
765 math-fet-x)))))
766 (math-build-polynomial-expr p math-fet-x)) ; can't factor it.
767
768 ;; Separate out the squared terms (Knuth exercise 4.6.2-34).
769 ;; This step also divides out the content of the polynomial.
770 (let* ((cabs (math-poly-gcd-list p))
771 (csign (if (math-negp (nth (1- (length p)) p)) -1 1))
772 (t1s (math-mul-list t1 csign))
773 (uu nil)
774 (v (car (math-poly-div-coefs p t1s)))
775 (w (car (math-poly-div-coefs t2 t1s))))
776 (while
777 (not (math-poly-zerop
778 (setq t2 (math-poly-simplify
779 (math-poly-mix
780 w 1 (math-poly-deriv-coefs v) -1)))))
781 (setq t1 (math-poly-gcd-coefs v t2)
782 uu (cons t1 uu)
783 v (car (math-poly-div-coefs v t1))
784 w (car (math-poly-div-coefs t2 t1))))
785 (setq t1 (length uu)
786 t2 (math-accum-factors (math-factor-poly-coefs v t)
787 (1+ t1) 1))
788 (while uu
789 (setq t2 (math-accum-factors (math-factor-poly-coefs
790 (car uu) t)
791 t1 t2)
792 t1 (1- t1)
793 uu (cdr uu)))
794 (math-accum-factors (math-mul cabs csign) 1 t2))))
795
796 ;; Factoring modulo a prime.
797 ((and (= (length (setq temp (math-poly-gcd-coefs
798 p (math-poly-deriv-coefs p))))
799 (length p)))
800 (setq p (car temp))
801 (while (cdr temp)
802 (setq temp (nthcdr (nth 2 math-poly-modulus) temp)
803 p (cons (car temp) p)))
804 (and (setq temp (math-factor-poly-coefs p))
805 (math-pow temp (nth 2 math-poly-modulus))))
806 (t
807 (math-reject-arg nil "*Modulo factorization not yet implemented")))))
808
809 (defun math-poly-deriv-coefs (p)
810 (let ((n 1)
811 (dp nil))
812 (while (setq p (cdr p))
813 (setq dp (cons (math-mul (car p) n) dp)
814 n (1+ n)))
815 (nreverse dp)))
816
817 (defun math-factor-contains (x a)
818 (if (equal x a)
819 1
820 (if (memq (car-safe x) '(+ - * / neg))
821 (let ((sum 0))
822 (while (setq x (cdr x))
823 (setq sum (+ sum (math-factor-contains (car x) a))))
824 sum)
825 (if (and (eq (car-safe x) '^)
826 (natnump (nth 2 x)))
827 (* (math-factor-contains (nth 1 x) a) (nth 2 x))
828 0))))
829
830
831
832
833
834 ;;; Merge all quotients and expand/simplify the numerator
835 (defun calcFunc-nrat (expr)
836 (if (math-any-floats expr)
837 (setq expr (calcFunc-pfrac expr)))
838 (if (or (math-vectorp expr)
839 (assq (car-safe expr) calc-tweak-eqn-table))
840 (cons (car expr) (mapcar 'calcFunc-nrat (cdr expr)))
841 (let* ((calc-prefer-frac t)
842 (res (math-to-ratpoly expr))
843 (num (math-simplify (math-sort-terms (calcFunc-expand (car res)))))
844 (den (math-simplify (math-sort-terms (calcFunc-expand (cdr res)))))
845 (g (math-poly-gcd num den)))
846 (or (eq g 1)
847 (let ((num2 (math-poly-div num g))
848 (den2 (math-poly-div den g)))
849 (and (eq (cdr num2) 0) (eq (cdr den2) 0)
850 (setq num (car num2) den (car den2)))))
851 (math-simplify (math-div num den)))))
852
853 ;;; Returns expressions (num . denom).
854 (defun math-to-ratpoly (expr)
855 (let ((res (math-to-ratpoly-rec expr)))
856 (cons (math-simplify (car res)) (math-simplify (cdr res)))))
857
858 (defun math-to-ratpoly-rec (expr)
859 (cond ((Math-primp expr)
860 (cons expr 1))
861 ((memq (car expr) '(+ -))
862 (let ((r1 (math-to-ratpoly-rec (nth 1 expr)))
863 (r2 (math-to-ratpoly-rec (nth 2 expr))))
864 (if (equal (cdr r1) (cdr r2))
865 (cons (list (car expr) (car r1) (car r2)) (cdr r1))
866 (if (eq (cdr r1) 1)
867 (cons (list (car expr)
868 (math-mul (car r1) (cdr r2))
869 (car r2))
870 (cdr r2))
871 (if (eq (cdr r2) 1)
872 (cons (list (car expr)
873 (car r1)
874 (math-mul (car r2) (cdr r1)))
875 (cdr r1))
876 (let ((g (math-poly-gcd (cdr r1) (cdr r2))))
877 (let ((d1 (and (not (eq g 1)) (math-poly-div (cdr r1) g)))
878 (d2 (and (not (eq g 1)) (math-poly-div
879 (math-mul (car r1) (cdr r2))
880 g))))
881 (if (and (eq (cdr d1) 0) (eq (cdr d2) 0))
882 (cons (list (car expr) (car d2)
883 (math-mul (car r2) (car d1)))
884 (math-mul (car d1) (cdr r2)))
885 (cons (list (car expr)
886 (math-mul (car r1) (cdr r2))
887 (math-mul (car r2) (cdr r1)))
888 (math-mul (cdr r1) (cdr r2)))))))))))
889 ((eq (car expr) '*)
890 (let* ((r1 (math-to-ratpoly-rec (nth 1 expr)))
891 (r2 (math-to-ratpoly-rec (nth 2 expr)))
892 (g (math-mul (math-poly-gcd (car r1) (cdr r2))
893 (math-poly-gcd (cdr r1) (car r2)))))
894 (if (eq g 1)
895 (cons (math-mul (car r1) (car r2))
896 (math-mul (cdr r1) (cdr r2)))
897 (cons (math-poly-div-exact (math-mul (car r1) (car r2)) g)
898 (math-poly-div-exact (math-mul (cdr r1) (cdr r2)) g)))))
899 ((eq (car expr) '/)
900 (let* ((r1 (math-to-ratpoly-rec (nth 1 expr)))
901 (r2 (math-to-ratpoly-rec (nth 2 expr))))
902 (if (and (eq (cdr r1) 1) (eq (cdr r2) 1))
903 (cons (car r1) (car r2))
904 (let ((g (math-mul (math-poly-gcd (car r1) (car r2))
905 (math-poly-gcd (cdr r1) (cdr r2)))))
906 (if (eq g 1)
907 (cons (math-mul (car r1) (cdr r2))
908 (math-mul (cdr r1) (car r2)))
909 (cons (math-poly-div-exact (math-mul (car r1) (cdr r2)) g)
910 (math-poly-div-exact (math-mul (cdr r1) (car r2))
911 g)))))))
912 ((and (eq (car expr) '^) (integerp (nth 2 expr)))
913 (let ((r1 (math-to-ratpoly-rec (nth 1 expr))))
914 (if (> (nth 2 expr) 0)
915 (cons (math-pow (car r1) (nth 2 expr))
916 (math-pow (cdr r1) (nth 2 expr)))
917 (cons (math-pow (cdr r1) (- (nth 2 expr)))
918 (math-pow (car r1) (- (nth 2 expr)))))))
919 ((eq (car expr) 'neg)
920 (let ((r1 (math-to-ratpoly-rec (nth 1 expr))))
921 (cons (math-neg (car r1)) (cdr r1))))
922 (t (cons expr 1))))
923
924
925 (defun math-ratpoly-p (expr &optional var)
926 (cond ((equal expr var) 1)
927 ((Math-primp expr) 0)
928 ((memq (car expr) '(+ -))
929 (let ((p1 (math-ratpoly-p (nth 1 expr) var))
930 p2)
931 (and p1 (setq p2 (math-ratpoly-p (nth 2 expr) var))
932 (max p1 p2))))
933 ((eq (car expr) '*)
934 (let ((p1 (math-ratpoly-p (nth 1 expr) var))
935 p2)
936 (and p1 (setq p2 (math-ratpoly-p (nth 2 expr) var))
937 (+ p1 p2))))
938 ((eq (car expr) 'neg)
939 (math-ratpoly-p (nth 1 expr) var))
940 ((eq (car expr) '/)
941 (let ((p1 (math-ratpoly-p (nth 1 expr) var))
942 p2)
943 (and p1 (setq p2 (math-ratpoly-p (nth 2 expr) var))
944 (- p1 p2))))
945 ((and (eq (car expr) '^)
946 (integerp (nth 2 expr)))
947 (let ((p1 (math-ratpoly-p (nth 1 expr) var)))
948 (and p1 (* p1 (nth 2 expr)))))
949 ((not var) 1)
950 ((math-poly-depends expr var) nil)
951 (t 0)))
952
953
954 (defun calcFunc-apart (expr &optional var)
955 (cond ((Math-primp expr) expr)
956 ((eq (car expr) '+)
957 (math-add (calcFunc-apart (nth 1 expr) var)
958 (calcFunc-apart (nth 2 expr) var)))
959 ((eq (car expr) '-)
960 (math-sub (calcFunc-apart (nth 1 expr) var)
961 (calcFunc-apart (nth 2 expr) var)))
962 ((and var (not (math-ratpoly-p expr var)))
963 (math-reject-arg expr "Expected a rational function"))
964 (t
965 (let* ((calc-prefer-frac t)
966 (rat (math-to-ratpoly expr))
967 (num (car rat))
968 (den (cdr rat)))
969 (or var
970 (setq var (math-polynomial-base den)))
971 (if (not (math-ratpoly-p expr var))
972 (math-reject-arg expr "Expected a rational function")
973 (let* ((qr (math-poly-div num den))
974 (q (car qr))
975 (r (cdr qr)))
976 (math-add q (or (and var
977 (math-expr-contains den var)
978 (math-partial-fractions r den var))
979 (math-div r den)))))))))
980
981
982 (defun math-padded-polynomial (expr var deg)
983 "Return a polynomial as list of coefficients.
984 If EXPR is of the form \"a + bx + cx^2 + ...\" in the variable VAR, return
985 the list (a b c ...) with at least DEG elements, else return NIL."
986 (let ((p (math-is-polynomial expr var deg)))
987 (append p (make-list (- deg (length p)) 0))))
988
989 (defun math-partial-fractions (r den var)
990 "Return R divided by DEN expressed in partial fractions of VAR.
991 All whole factors of DEN have already been split off from R.
992 If no partial fraction representation can be found, return nil."
993 (let* ((fden (calcFunc-factors den var))
994 (tdeg (math-polynomial-p den var))
995 (fp fden)
996 (dlist nil)
997 (eqns 0)
998 (lz nil)
999 (tz (make-list (1- tdeg) 0))
1000 (calc-matrix-mode 'scalar))
1001 (and (not (and (= (length fden) 2) (eq (nth 2 (nth 1 fden)) 1)))
1002 (progn
1003 (while (setq fp (cdr fp))
1004 (let ((rpt (nth 2 (car fp)))
1005 (deg (math-polynomial-p (nth 1 (car fp)) var))
1006 dnum dvar deg2)
1007 (while (> rpt 0)
1008 (setq deg2 deg
1009 dnum 0)
1010 (while (> deg2 0)
1011 (setq dvar (append '(vec) lz '(1) tz)
1012 lz (cons 0 lz)
1013 tz (cdr tz)
1014 deg2 (1- deg2)
1015 dnum (math-add dnum (math-mul dvar
1016 (math-pow var deg2)))
1017 dlist (cons (and (= deg2 (1- deg))
1018 (math-pow (nth 1 (car fp)) rpt))
1019 dlist)))
1020 (let ((fpp fden)
1021 (mult 1))
1022 (while (setq fpp (cdr fpp))
1023 (or (eq fpp fp)
1024 (setq mult (math-mul mult
1025 (math-pow (nth 1 (car fpp))
1026 (nth 2 (car fpp)))))))
1027 (setq dnum (math-mul dnum mult)))
1028 (setq eqns (math-add eqns (math-mul dnum
1029 (math-pow
1030 (nth 1 (car fp))
1031 (- (nth 2 (car fp))
1032 rpt))))
1033 rpt (1- rpt)))))
1034 (setq eqns (math-div (cons 'vec (math-padded-polynomial r var tdeg))
1035 (math-transpose
1036 (cons 'vec
1037 (mapcar
1038 (function
1039 (lambda (x)
1040 (cons 'vec (math-padded-polynomial
1041 x var tdeg))))
1042 (cdr eqns))))))
1043 (and (math-vectorp eqns)
1044 (let ((res 0)
1045 (num nil))
1046 (setq eqns (nreverse eqns))
1047 (while eqns
1048 (setq num (cons (car eqns) num)
1049 eqns (cdr eqns))
1050 (if (car dlist)
1051 (setq num (math-build-polynomial-expr
1052 (nreverse num) var)
1053 res (math-add res (math-div num (car dlist)))
1054 num nil))
1055 (setq dlist (cdr dlist)))
1056 (math-normalize res)))))))
1057
1058
1059
1060 (defun math-expand-term (expr)
1061 (cond ((and (eq (car-safe expr) '*)
1062 (memq (car-safe (nth 1 expr)) '(+ -)))
1063 (math-add-or-sub (list '* (nth 1 (nth 1 expr)) (nth 2 expr))
1064 (list '* (nth 2 (nth 1 expr)) (nth 2 expr))
1065 nil (eq (car (nth 1 expr)) '-)))
1066 ((and (eq (car-safe expr) '*)
1067 (memq (car-safe (nth 2 expr)) '(+ -)))
1068 (math-add-or-sub (list '* (nth 1 expr) (nth 1 (nth 2 expr)))
1069 (list '* (nth 1 expr) (nth 2 (nth 2 expr)))
1070 nil (eq (car (nth 2 expr)) '-)))
1071 ((and (eq (car-safe expr) '/)
1072 (memq (car-safe (nth 1 expr)) '(+ -)))
1073 (math-add-or-sub (list '/ (nth 1 (nth 1 expr)) (nth 2 expr))
1074 (list '/ (nth 2 (nth 1 expr)) (nth 2 expr))
1075 nil (eq (car (nth 1 expr)) '-)))
1076 ((and (eq (car-safe expr) '^)
1077 (memq (car-safe (nth 1 expr)) '(+ -))
1078 (integerp (nth 2 expr))
1079 (if (and
1080 (or (math-known-matrixp (nth 1 (nth 1 expr)))
1081 (math-known-matrixp (nth 2 (nth 1 expr)))
1082 (and
1083 calc-matrix-mode
1084 (not (eq calc-matrix-mode 'scalar))
1085 (not (and (math-known-scalarp (nth 1 (nth 1 expr)))
1086 (math-known-scalarp (nth 2 (nth 1 expr)))))))
1087 (> (nth 2 expr) 1))
1088 (if (= (nth 2 expr) 2)
1089 (math-add-or-sub (list '* (nth 1 (nth 1 expr)) (nth 1 expr))
1090 (list '* (nth 2 (nth 1 expr)) (nth 1 expr))
1091 nil (eq (car (nth 1 expr)) '-))
1092 (math-add-or-sub (list '* (nth 1 (nth 1 expr))
1093 (list '^ (nth 1 expr)
1094 (1- (nth 2 expr))))
1095 (list '* (nth 2 (nth 1 expr))
1096 (list '^ (nth 1 expr)
1097 (1- (nth 2 expr))))
1098 nil (eq (car (nth 1 expr)) '-)))
1099 (if (> (nth 2 expr) 0)
1100 (or (and (or (> math-mt-many 500000) (< math-mt-many -500000))
1101 (math-expand-power (nth 1 expr) (nth 2 expr)
1102 nil t))
1103 (list '*
1104 (nth 1 expr)
1105 (list '^ (nth 1 expr) (1- (nth 2 expr)))))
1106 (if (< (nth 2 expr) 0)
1107 (list '/ 1 (list '^ (nth 1 expr) (- (nth 2 expr)))))))))
1108 (t expr)))
1109
1110 (defun calcFunc-expand (expr &optional many)
1111 (math-normalize (math-map-tree 'math-expand-term expr many)))
1112
1113 (defun math-expand-power (x n &optional var else-nil)
1114 (or (and (natnump n)
1115 (memq (car-safe x) '(+ -))
1116 (let ((terms nil)
1117 (cterms nil))
1118 (while (memq (car-safe x) '(+ -))
1119 (setq terms (cons (if (eq (car x) '-)
1120 (math-neg (nth 2 x))
1121 (nth 2 x))
1122 terms)
1123 x (nth 1 x)))
1124 (setq terms (cons x terms))
1125 (if var
1126 (let ((p terms))
1127 (while p
1128 (or (math-expr-contains (car p) var)
1129 (setq terms (delq (car p) terms)
1130 cterms (cons (car p) cterms)))
1131 (setq p (cdr p)))
1132 (if cterms
1133 (setq terms (cons (apply 'calcFunc-add cterms)
1134 terms)))))
1135 (if (= (length terms) 2)
1136 (let ((i 0)
1137 (accum 0))
1138 (while (<= i n)
1139 (setq accum (list '+ accum
1140 (list '* (calcFunc-choose n i)
1141 (list '*
1142 (list '^ (nth 1 terms) i)
1143 (list '^ (car terms)
1144 (- n i)))))
1145 i (1+ i)))
1146 accum)
1147 (if (= n 2)
1148 (let ((accum 0)
1149 (p1 terms)
1150 p2)
1151 (while p1
1152 (setq accum (list '+ accum
1153 (list '^ (car p1) 2))
1154 p2 p1)
1155 (while (setq p2 (cdr p2))
1156 (setq accum (list '+ accum
1157 (list '* 2 (list '*
1158 (car p1)
1159 (car p2))))))
1160 (setq p1 (cdr p1)))
1161 accum)
1162 (if (= n 3)
1163 (let ((accum 0)
1164 (p1 terms)
1165 p2 p3)
1166 (while p1
1167 (setq accum (list '+ accum (list '^ (car p1) 3))
1168 p2 p1)
1169 (while (setq p2 (cdr p2))
1170 (setq accum (list '+
1171 (list '+
1172 accum
1173 (list '* 3
1174 (list
1175 '*
1176 (list '^ (car p1) 2)
1177 (car p2))))
1178 (list '* 3
1179 (list
1180 '* (car p1)
1181 (list '^ (car p2) 2))))
1182 p3 p2)
1183 (while (setq p3 (cdr p3))
1184 (setq accum (list '+ accum
1185 (list '* 6
1186 (list '*
1187 (car p1)
1188 (list
1189 '* (car p2)
1190 (car p3))))))))
1191 (setq p1 (cdr p1)))
1192 accum))))))
1193 (and (not else-nil)
1194 (list '^ x n))))
1195
1196 (defun calcFunc-expandpow (x n)
1197 (math-normalize (math-expand-power x n)))
1198
1199 (provide 'calc-poly)
1200
1201 ;;; calc-poly.el ends here