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