1 ;;; -*- Mode: Lisp; Package: Macsyma -*- ;;;
2 ;;; (c) Copyright 1984 the Regents of the University of California. ;;;
3 ;;; All Rights Reserved. ;;;
4 ;;; This work was produced under the sponsorship of the ;;;
5 ;;; U.S. Department of Energy. The Government retains ;;;
6 ;;; certain rights therein. ;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9 (macsyma-module seqopt
)
11 (defmvar $sequence_optim_prefix
'$opt
12 "String used to prefix all optimized temporaries arising from a
13 call to SEQUENCE_OPTIMIZE."
14 modified-commands
'$sequence_optimize
)
16 (defmvar $sequence_optim_counter
1
17 "Integer index used to uniquely identify all optimized temporaries
18 arising from a call to SEQUENCE_OPTIMIZE."
20 modified-commands
'$sequence_optimize
)
22 (defmvar $sequence_optim_suffix
's
23 "String used to suffix all optimized temporaries arising from a
24 call to SEQUENCE_OPTIMIZE, as well as names generated by CRAY_FORTRAN for
25 subexpressions which have been broken out of an expression which is too
26 large for the CFT compiler."
27 modified-commands
'($sequence_optimize $cray_fortran
))
29 (defmvar $save_optim_info nil
30 "Flag which, if TRUE, causes the common subexpressions which
31 SEQUENCE_OPTIMIZE finds to be saved as equations on the MACSYMA list
34 modified-commands
'$sequence_optimize
)
36 (defmvar $optim_equivs
(list '(mlist simp
))
37 "Macsyma list of equations for the common subexpressions which
38 SEQUENCE_OPTIMIZE finds when SAVE_OPTIM_INFO is TRUE."
39 modified-commands
'$sequence_optimize
)
41 (defmvar $optim_additions
(list '(mlist simp
))
42 "Macsyma list of equations for the subexpressions which it is known
43 a priori will occur more than once in a sequence of code to be optimized."
44 modified-commands
'$pre_optimize
)
46 (defmvar $merge_ops
(list '(mlist simp
) '$cvmgp
'$cvmgt
)
47 "A MACSYMA list of currently known CRAY-1 vector merge operations."
48 modified-commands
'($sequence_optimize $expense
))
50 (defmvar $cost_float_power
(+ $cost_exp $cost_sin_cos_log
)
51 "The expense of computing a floating point power in terms of scalar
52 floating point additions on the CRAY-1(For further discussion do:
53 DESCRIBE(COST_RECIPROCAL) )."
55 modified-commands
'($expense $gather_exponents
))
57 (defvar optim-vars nil
58 "MACSYMA list of generated names for common subexpressions(Not used if
59 a list equations is passed to SEQUENCE_OPTIMIZE).")
63 (defmacro make-expt
(base exponent
) ``((mexpt simp
) ,,base
,,exponent
))
65 (defmacro base
(x) `(cadr ,x
))
67 (defmacro exponent
(x) `(caddr ,x
))
69 (defmacro mquotientp
(x) `(and (not (atom ,x
)) (eq (caar ,x
) 'mquotient
)))
71 ;; $SEQUENCE_OPTIMIZE takes a Macsyma expression or list of simple equations
72 ;; and returns a LIST which contains a series of equivalences for the common
73 ;; subexpressions and the reduced equations or expression.
74 ;; These subexpressions are found by hashing them.
76 (defun alike1-hash (exp)
79 (do ((n (alike1-hash (caar exp
))
80 (+ n
(alike1-hash (car arg_list
))))
81 (arg_list (cdr exp
) (cdr arg_list
)))
83 27449.
)) ; a prime number < 2^15 = PRIME(3000)
85 (defun $sequence_optimize
(x)
87 (fillarray 'subexp
(list nil
))
89 (do ((chk (cdr x
) (cdr chk
)))
91 (or (and (not (atom (car chk
)))
92 (eq (caaar chk
) 'mequal
)
93 ($mapatom
(cadar chk
)))
94 (merror "List passed to SEQUENCE_OPTIMIZE of incorrect form. Bad element is ~%~M" (car chk
))))
95 (setq optim-vars
(append (list '(mlist)) nil
)))
96 (setq x
(collapse (fix-unary-minus (optim-format ($gather_exponents
(copy-tree x
))))))
97 (if (atom x
) (return x
))
100 (and $save_optim_info
101 (setq $optim_equivs
(append $optim_equivs
(copy-tree setqs
))))
102 (return (prog1 (cond ((null setqs
) x
)
105 (do ((opt-con setqs
(cdr opt-con
)))
107 (let ((rhs-eqn (caddar opt-con
)))
108 (do ((equivs scan
(cdr equivs
)))
110 (rplacd scan
(append (ncons (car opt-con
)) (cdr scan
)))
111 (setq scan
(cdr scan
)))
112 (or (freeof (cadadr equivs
) rhs-eqn
)
113 (setq scan
(cdr equivs
))))))))
114 ((or (not (eq 'mprog
(caar x
)))
115 (and ($listp
(cadr x
)) (cdadr x
)))
116 `((mprog) ,optim-vars
,.setqs
,x
))
117 (t `((mprog) ,optim-vars
,.
(nconc setqs
(cddr x
)))))
118 (setq optim-vars nil
)
119 (fillarray 'subexp
(list nil
))))))
121 (defun copy-to-pntr (x y
)
122 (do ((redo x
(cdr redo
))
123 (new nil
`(,.new
,(car redo
))))
126 (defun recip-1 (expon)
127 (or (and (numberp expon
) (minusp expon
))
128 (and (not (atom expon
))
129 (let ((op (caar expon
)))
130 (or (and (eq op
'mtimes
) (equal (cadr expon
) -
1))
131 (and (eq op
'rat
) (minusp (cadr expon
)))
134 (defun reciprocalp (x)
136 (let ((expon (exponent x
)))
137 (cond ((mquotientp expon
) (recip-1 (cadr expon
)))
138 (t (recip-1 expon
))))))
140 (defun gen-negative (x)
141 (cond ((mmminusp x
) (cadr x
))
142 ((mquotientp x
) `((mquotient) ,(mul -
1 (cadr x
)) ,(caddr x
)))
146 (cond ((cdr x
) `((mtimes) ,@x
))
149 (defun optim-format (x)
151 ((and (eq 'rat
(caar x
)) (minusp (cadr x
)))
152 `((mminus) ((rat) ,(- (cadr x
)) ,(caddr x
))))
153 ((and (eq 'mquotient
(caar x
)) (not (equal 1 (cadr x
))))
154 (let ((nmr (cadr x
)))
155 (optim-format `((mtimes simp
) ,@(cond ((mtimesp nmr
) (cdr nmr
))
157 ((mquotient) 1 ,(caddr x
))))))
158 ((eq 'mexpt
(caar x
)) (opt-expt x
))
159 ((eq 'mtimes
(caar x
))
160 (do ((next (cdr x
) (cdr next
))
165 (let ((recip `((mquotient) 1 ,(mul-list denominator
))))
167 (let ((prod?
(mul-list numerator
)))
168 (cond ((mtimesp prod?
)
169 (nconc prod?
(ncons recip
)))
170 (t `((mtimes) ,prod?
,recip
)))))
172 (numerator (mul-list numerator
))
174 (let ((obj (car next
)))
175 (cond ((reciprocalp obj
)
176 (let* ((expon (exponent obj
))
177 (optim-expt (let ((mbase (base obj
)))
178 (cond ((equal expon -
1)
179 (optim-format mbase
))
181 (opt-expt (make-expt mbase
(gen-negative expon
))))))))
184 (cond ((mtimesp optim-expt
) (cdr optim-expt
))
185 (t (ncons optim-expt
)))))
187 (do ((seplist (cdr x
) (cdr seplist
)))
189 (let ((element (car seplist
)))
190 (or (reciprocalp element
)
191 (setq numerator
`(,.numerator
,element
))))))))
193 (let ((result (optim-format obj
)))
196 (do ((seplist (cdr x
) (cdr seplist
)))
198 (let ((element (car seplist
)))
199 (or (reciprocalp element
)
200 (setq numerator
`(,.numerator
,element
))))))
201 (and (or numerator denominator
(not (eq obj result
)))
202 (setq numerator
(nconc numerator
203 (cond ((and (mexptp obj
) (mtimesp result
))
204 (copy-tree (cdr result
)))
205 (t (ncons result
))))))))))))
207 (do ((next (cdr x
) (cdr next
))
212 (let* ((obj (car next
))
213 (result (optim-format obj
)))
216 (setq new
(copy-to-pntr x next
)))
217 (and (or new
(not (eq obj result
)))
218 (setq new
`(,.new
,result
))))))))
221 (let ((osym-base (base x
)) (oexp (exponent x
)))
222 (let ((sym-base (optim-format osym-base
)) (exp (optim-format oexp
)))
223 (cond ((reciprocalp x
)
224 `((mquotient) 1 ,(cond ((equal -
1 exp
) sym-base
)
225 (t (opt-expt (make-expt sym-base
(gen-negative exp
)))))))
226 ((and (ratnump exp
) (equal 2 (caddr exp
)))
227 (setq exp
(cadr exp
))
228 (cond ((equal 1 exp
) `((%sqrt
) ,sym-base
))
229 (t (let ((int-exp (quotient exp
2)))
230 `((mtimes) ((%sqrt
) ,sym-base
)
231 ,(cond ((equal int-exp
1) sym-base
)
232 (t (make-expt sym-base int-exp
))))))))
234 (cond ((and (eq osym-base sym-base
) (eq oexp exp
)) x
)
235 (t (make-expt sym-base exp
))))))))
237 ;; the following two functions were motivated by an inability of the
238 ;; cray merge functions to cope with a unary minus.
240 (defun disp-negate (x)
242 (let ((coeff (cadr x
)))
243 (cond ((and (fixnump coeff
) (minusp coeff
))
244 (append `((mtimes) ,(- coeff
)) (cddr x
)))
245 (t `((mminus) ,x
)))))
246 ((mnump x
) (mul -
1 x
))
247 ((or (atom x
) (not (eq (caar x
) 'mminus
))) `((mminus) ,x
))
250 (defun fix-unary-minus (x)
251 (cond (($mapatom x
) x
)
252 ((eq (caar x
) 'mtimes
)
253 (mapc 'fix-unary-minus
(cdr x
))
254 (let ((sign (cadr x
)))
255 (cond ((and (fixnump sign
) (minusp sign
))
256 (cond ((equal sign -
1)
257 (let ((chk-merge (caddr x
)))
258 (cond ((and (not (atom chk-merge
))
259 (member (caar chk-merge
) $merge_ops
:test
#'eq
))
260 (rplacd (cdr x
) (append `(((,(caar chk-merge
)) ,(disp-negate (cadr chk-merge
))
261 ,(disp-negate (caddr chk-merge
))
262 ,(cadddr chk-merge
)))
264 (cond ((cdddr x
) (rplacd x
(cddr x
)) x
)
266 (t `((mminus) ,(cond ((cdddr x
)
267 (rplacd x
(cddr x
)) x
)
269 (t `((mminus) ,(append `((mtimes) ,(- sign
)) (cddr x
))))))
271 (t (do ((search (cdr x
) (cdr search
)))
273 (let* ((obj (car search
)) (new (fix-unary-minus obj
)))
274 (or (eq new obj
) (rplaca search new
)))))))
279 (let ((n (logand 63.
(alike1-hash x
))))
280 (do ((l (cdr x
) (cdr l
)))
282 (let* ((carl (car l
)) (res (collapse carl
)))
283 (or (eq carl res
) (rplaca l res
))))
284 (do ((l (subexp n
) (cdr l
)))
285 ((null l
) (setf (subexp n
) (cons (list x
) (subexp n
))) x
)
286 (if (alike1 x
(caar l
)) (return (caar l
)))))))
292 (setq x
(assoc x
(subexp (logand 63.
(alike1-hash x
))) :test
#'eq
))
293 (cond ((null (cdr x
))
295 (mapc 'comexp
(cdar x
)))
296 (t (rplacd x
(1+ (cdr x
))))))))
300 ((and (member 'array
(cdar x
) :test
#'eq
) (not (mget (caar x
) 'arrayfun-mode
))) x
)
301 ((eq 'rat
(caar x
)) x
)
303 (let ((xpair (assoc x
(subexp (logand 63.
(alike1-hash x
))) :test
#'eq
))
304 (nx (do ((l (cdr x
) (cdr l
))
305 (c (list (car x
)) (cons (optim (car l
)) c
)))
306 ((null l
) (nreverse c
)))))
307 (let ((tmp (cdr xpair
))
308 (sym (do ((lk (cdr $optim_equivs
) (cdr lk
)))
310 (and (alike1 nx
(caddar lk
))
311 (return (cadar lk
))))))
315 (mformat nil
"c - earlier opt-vect, ~M, occurs ~M time(s)" sym tmp
)
319 (let ((sym (getvar)))
321 (setq setqs
`(,.setqs
,(list (cond (optim-vars (list 'msetq
))
324 (mformat nil
"c - there are ~M occurrences of ~M" tmp sym
)
326 (t tmp
))))))) ;;; Should this be an error?
329 (let ((newvar (implode (nconc (exploden $sequence_optim_prefix
)
330 (exploden $sequence_optim_counter
)
331 (exploden $sequence_optim_suffix
)))))
332 (incf $sequence_optim_counter
)
333 (if optim-vars
(setq optim-vars
`(,.optim-vars
,newvar
)))
336 ;;; The following will not PRE_OPTIMIZE top-level forms.
338 (defun $pre_optimize
(x)
340 ((eq (caar x
) '$cvmgp
)
341 (let ((term3 (cadddr x
))
342 (opt-list (append $optim_equivs
(cdr $optim_additions
))))
344 (and (eq (caar term3
) 'mtimes
)
345 (equal (cadr term3
) -
1)
346 (let ((obj (caddr term3
))
347 (two-term (= (length term3
) 3)))
348 (or (and two-term
($mapatom obj
))
349 (do ((l (cdr opt-list
) (cdr l
)))
351 (let ((rhs (caddar l
)))
352 (cond ((and two-term
(alike1 rhs obj
))
353 (rplaca (cdddr x
) (mul -
1 (cadar l
)))
356 (rplaca (cdddr x
) (cadar l
))
358 (do ((l (cdr opt-list
) (cdr l
)))
360 (let ((rhs (caddar l
)))
361 (cond ((alike1 rhs term3
)
362 (rplaca (cdddr x
) (cadar l
))
364 ((and (eq (caar rhs
) 'mtimes
)
365 (equal (cadr rhs
) -
1)
367 (alike1 (caddr rhs
) term3
))
368 (rplaca (cdddr x
) (mul (cadar l
) -
1))
370 (let ((name (getvar)))
371 (setq $optim_additions
372 `(,@$optim_additions
((mequal simp
) ,name
,term3
)))
373 (rplaca (cdddr x
) name
)))))
374 (t (do ((terms (cdr x
) (cdr terms
)))
376 (let ((obj (car terms
)))
378 (do ((lk (cdr $optim_equivs
) (cdr lk
)))
380 (and (alike1 obj
(caddar lk
))
381 (rplaca terms
(cadar lk
))
384 (defun $collapse_pre_optims
(x)
386 ((do ((lk (cdr $optim_equivs
) (cdr lk
)))
388 (and (alike1 x
(caddar lk
))
389 (return (cadar lk
)))))
390 (t (do ((terms (cdr x
) (cdr terms
))
393 (cond ((or success
(not (eq (caar x
) 'mtimes
))) x
)
394 (t (do ((l (cdr x
) (cdr l
))
397 (let ((saved (car l
)))
399 ((eq (caar saved
) '$cvmgp
)
400 (rplacd follow
(cdr l
))
401 (let* ((pminus (equal (cadr x
) -
1))
402 (new (do ((lk (cdr $optim_equivs
) (cdr lk
)))
404 (let ((rhs (caddar lk
)))
405 (cond ((alike1 x rhs
)
407 (t (and (eq (caar rhs
) 'mtimes
)
409 (alike1 (cddr x
) (cdr rhs
)))
410 ((equal (cadr rhs
) -
1)
411 (alike1 (cdr x
) (cddr rhs
))))
412 (return (mul -
1 (cadar lk
))))))))))
413 (return (cond ((eq new x
)
414 (rplacd follow
`(,saved
,@(cdr follow
)))
416 (t (mul new saved
))))))))))))
417 (let* ((obj (car terms
)) (new-obj ($collapse_pre_optims obj
)))
419 (and (setq success t
)
420 (rplaca terms new-obj
))))))))
422 (defun product-base (x y
)
423 (muln (append (cond ((mtimesp x
) (cdr x
))
425 (cond ((mtimesp y
) (cdr y
))
429 (defun floating-exponent-gather (x)
432 (do ((next (cdr x
) (cdr next
))
433 (xfol (cdr x
) (cdr xfol
))
439 (let* ((obj (car next
)) (result obj
))
441 (let ((expon (exponent result
)))
442 (and (not (fixnump expon
))
443 (do ((remain (cdr next
) (cdr remain
)))
445 (let ((powered?
(car remain
)))
446 (and (mexptp powered?
)
447 (let ((expon-2 (exponent powered?
)))
448 (and (not (fixnump expon-2
))
449 (let ((intdif (sub expon expon-2
)))
450 (and (fixnump intdif
)
451 (let ((pf (> intdif
0))
453 (declare (fixnum ab
))
454 (cond ((or (zerop ab
)
455 (> (+ $cost_float_power
457 (cond (pf ($expense expon-2
))
458 (t ($expense expon
))))
460 (let ((mbase (base result
)))
461 (cond ((mtimesp mbase
) ($expense mbase
))
464 (let ((mbase (base powered?
)))
465 (cond ((mtimesp mbase
) ($expense mbase
))
467 (multiplies-in-nth-power (abs ab
)))))
468 (cond ((not modified
)
470 next
(append next nil
))
471 (setq remain
(member powered? next
:test
#'eq
))
472 (setq powered?
(car remain
))))
474 (let ((mbase (base result
)))
476 (cond ((equal ab
1) mbase
)
477 (t (make-expt mbase ab
))))
478 (rplaca remain
(make-expt (product-base mbase
(base powered?
)) (exponent powered?
))))
481 (setq result
(make-expt (product-base (base result
) (base powered?
)) (exponent result
)))
483 (setq next
(delete powered? next
:test
#'eq
)))
486 (mbase (base powered?
)))
487 (cond ((equal pabs
1)
488 (cond ((mtimesp mbase
)
489 (setq next
(nconc next
(cdr mbase
)))
490 (setq remain
(member powered? next
:test
#'eq
))
491 (setq next
(delete powered? next
:test
#'eq
)))
492 (t (rplaca remain mbase
))))
493 (t (rplaca remain
(make-expt mbase pabs
))))))))))))))))))))))
494 (setq result
(floating-exponent-gather result
))
497 (setq new
(copy-to-pntr (cdr x
) xfol
)))
498 (and (or new
(not (eq obj result
)))
500 (cond ((mtimesp result
)
501 (copy-tree (cdr result
)))
502 (t (ncons result
)))))))))
504 (do ((next (cdr x
) (cdr next
))
509 (let* ((obj (car next
))
510 (result (floating-exponent-gather obj
)))
513 (setq new
(copy-to-pntr x next
)))
514 (and (or new
(not (eq obj result
)))
515 (setq new
`(,.new
,result
))))))))
517 (defmacro div-q
(x y
) `(div (simplify ,x
) (simplify ,y
)))
519 (defun fgcd-exponent-gather (x)
522 (do ((next (cdr x
) (cdr next
))
523 (xfol (cdr x
) (cdr xfol
))
529 (let* ((obj (car next
))
530 (result (fgcd-exponent-gather obj
)))
532 (let ((expon (exponent result
)))
533 (and (not (fixnump expon
))
534 (do ((allow-fix t nil
)
537 (do ((remain (cdr next
) (cdr remain
))
541 (or allow-fix
(setq repeat nil
))
543 (if (fixnump current-gcd
)
544 (<= (multiplies-in-nth-power current-gcd
)
547 (let* ((leadiv (gen-quotients (div-q expon current-gcd
)))
548 (a-single (equal leadiv
1))
549 (ints (and (not a-single
) (fixnump leadiv
))))
550 (do ((scan pntrs
(cdr scan
))
553 (multiplies-in-nth-power leadiv
)))
555 (interms (cond (ints (ncons (make-expt (base result
) leadiv
)))
557 (others (cond (ints ())
559 (let ((mbase (base result
)))
561 (cond ((mtimesp mbase
) (cdr mbase
))
563 (t (ncons (make-expt mbase leadiv
)))))))))
566 (let* ((prod-ints (muln interms nil
))
567 (try-ints-gather (integer-gathering prod-ints
))
568 (savings (- (+ (1+ (length pntrs
))
569 (- ($expense prod-ints
)
570 ($expense try-ints-gather
))
573 (declare (fixnum savings
))
574 (if (< savings
0) (return nil
))
575 (setq result
(make-expt (muln (nconc others
576 (cond ((mtimesp try-ints-gather
)
577 (cdr try-ints-gather
))
578 (t (ncons try-ints-gather
))))
582 (if (not a-single
) (return (setq repeat nil
)))
583 (setq result
(make-expt (muln others nil
) current-gcd
))))
584 (do ((rescan pntrs
(cdr rescan
)))
585 ((null rescan
) (setq repeat nil
))
586 (setq next
(delete (car rescan
) next
:test
#'eq
))))
587 (declare (fixnum save
))
588 (let* ((expt (car scan
))
589 (expon-2 (exponent expt
))
590 (nxdiv (gen-quotients (div-q expon-2 current-gcd
))))
591 (cond ((equal nxdiv
1)
593 save
(+ save $cost_float_power
)
594 others
(nconc others
(let ((mbase (base expt
)))
595 (cond ((mtimesp mbase
) (cdr mbase
))
596 (t (ncons mbase
)))))))
598 (setq save
(+ save
(- $cost_float_power
599 (multiplies-in-nth-power nxdiv
)))
600 interms
`(,.interms
,(make-expt (base expt
) nxdiv
))))
602 (setq others
`(,.others
,(make-expt (base expt
) nxdiv
))))))))))
603 (let ((powered?
(car remain
)))
604 (and (mexptp powered?
)
605 (let ((expon-2 (exponent powered?
)))
606 (and (not (fixnump expon-2
))
607 (let ((fgcd (gen-quotients ($gcd current-gcd expon-2
))))
608 (cond ((equal fgcd
1))
611 (alike1 fgcd expon-2
)
613 (or (fixnump (div-q expon fgcd
))
614 (fixnump (div-q expon-2 fgcd
)))))
615 (cond ((not modified
)
617 next
(append next nil
))
618 (setq remain
(member powered? next
:test
#'eq
))
619 (setq powered?
(car remain
))))
620 (setq current-gcd fgcd
621 pntrs
`(,.pntrs
,powered?
))))))))))))))
624 (setq new
(copy-to-pntr (cdr x
) xfol
)))
625 (and (or new
(not (eq obj result
)))
626 (setq new
`(,.new
,result
))))))
628 (do ((next (cdr x
) (cdr next
))
633 (let* ((obj (car next
))
634 (result (fgcd-exponent-gather obj
)))
637 (setq new
(copy-to-pntr x next
)))
638 (and (or new
(not (eq obj result
)))
639 (setq new
`(,.new
,result
))))))))
641 (defun integer-exponent-gather (x)
644 (do ((top x
(or new top
))
648 (do ((next (cdr top
) (cdr next
))
649 (xfol (cdr top
) (cdr xfol
))
652 (and new
(setq new
(muln new nil
))))
653 (let* ((obj (car next
)) (result obj
))
655 (let ((expon (exponent result
)))
657 (do ((remain (cdr next
) (cdr remain
)))
659 (let ((powered?
(car remain
)))
660 (and (mexptp powered?
)
661 (let ((expon-2 (exponent powered?
)))
662 (and (fixnump expon-2
)
663 (let* ((intdif (- expon expon-2
))
665 (declare (fixnum intdif
))
666 (cond ((or (zerop intdif
)
668 (let ((mbase (base result
)))
669 (cond ((mtimesp mbase
) ($expense mbase
))
672 (let ((mbase (base powered?
)))
673 (cond ((mtimesp mbase
) ($expense mbase
))
676 (multiplies-in-nth-power (abs intdif
)))
677 (multiplies-in-nth-power (max expon expon-2
))))
678 (cond ((not modified
)
680 next
(append next nil
))
681 (setq remain
(member powered? next
:test
#'eq
))
682 (setq powered?
(car remain
))))
684 (let ((mbase (base result
)))
686 (cond ((equal intdif
1) mbase
)
687 (t (make-expt mbase intdif
))))
688 (rplaca remain
(make-expt (product-base mbase
(base powered?
)) (exponent powered?
))))
691 (setq result
(make-expt (product-base (base result
) (base powered?
)) (exponent result
)))
692 (cond ((zerop intdif
)
693 (setq next
(delete powered? next
:test
#'eq
)))
695 (let ((pabs (- intdif
))
696 (mbase (base powered?
)))
697 (cond ((equal pabs
1)
698 (cond ((mtimesp mbase
)
699 (setq next
(nconc next
(cdr mbase
)))
700 (setq remain
(member powered? next
:test
#'eq
))
701 (setq next
(delete powered? next
:test
#'eq
)))
702 (t (rplaca remain mbase
))))
703 (t (rplaca remain
(make-expt mbase pabs
))))))))))))))))))))
704 (setq result
(integer-exponent-gather result
))
707 (setq new
(copy-to-pntr (cdr top
) xfol
)))
708 (and (or new
(not (eq obj result
)))
710 (cond ((mtimesp result
)
711 (copy-tree (cdr result
)))
712 (t (ncons result
))))))))))
714 (do ((next (cdr x
) (cdr next
))
719 (let* ((obj (car next
))
720 (result (integer-exponent-gather obj
)))
723 (setq new
(copy-to-pntr x next
)))
724 (and (or new
(not (eq obj result
)))
725 (setq new
`(,.new
,result
))))))))
727 (defun igcd-exponent-gather (x)
730 (do ((next (cdr x
) (cdr next
))
731 (xfol (cdr x
) (cdr xfol
))
737 (let* ((obj (car next
))
738 (result (igcd-exponent-gather obj
)))
740 (let ((expon (exponent result
)))
742 (do ((remain (cdr next
) (cdr remain
))
747 (do ((scan pntrs
(cdr scan
))
748 (newbase (let ((mbase (base result
)))
749 (cond ((equal expon current-gcd
)
750 (cond ((mtimesp mbase
) (cdr mbase
))
752 (t (ncons (make-expt mbase
(quotient expon current-gcd
))))))))
754 (setq result
(make-expt (muln newbase nil
) current-gcd
)))
755 (let* ((expt (car scan
))
756 (expon-2 (exponent expt
)))
757 (setq newbase
(nconc newbase
(let ((mbase (base expt
)))
758 (cond ((equal expon-2 current-gcd
)
759 (cond ((mtimesp mbase
) (cdr mbase
))
761 (t (ncons (make-expt mbase
(quotient expon-2 current-gcd
)))))))
762 next
(delete expt next
:test
#'eq
))))))
763 (declare (fixnum current-gcd
))
764 (let ((powered?
(car remain
)))
765 (and (mexptp powered?
)
766 (let ((expon-2 (exponent powered?
)))
767 (and (fixnump expon-2
)
768 (let ((intgcd (gcd current-gcd expon-2
)))
769 (cond ((not (equal intgcd
1))
770 (cond ((not modified
)
772 next
(append next nil
))
773 (setq remain
(member powered? next
:test
#'eq
))
774 (setq powered?
(car remain
))))
775 (setq current-gcd intgcd
776 pntrs
`(,.pntrs
,powered?
)))))))))))))
779 (setq new
(copy-to-pntr (cdr x
) xfol
)))
780 (and (or new
(not (eq obj result
)))
781 (setq new
`(,.new
,result
))))))
783 (do ((next (cdr x
) (cdr next
))
788 (let* ((obj (car next
))
789 (result (igcd-exponent-gather obj
)))
792 (setq new
(copy-to-pntr x next
)))
793 (and (or new
(not (eq obj result
)))
794 (setq new
`(,.new
,result
))))))))
796 (defun gen-quotients (x)
797 (cond (($mapatom x
) x
)
798 ((specrepp x
) (gen-quotients (specdisrep x
)))
799 ((eq 'mtimes
(caar x
))
800 (do ((next (cdr x
) (cdr next
))
805 (let ((den (mul-list denominator
)))
807 `((mquotient) ,(mul-list numerator
) ,den
))
808 (t `((mquotient) 1 ,den
)))))
809 (numerator (mul-list numerator
))
811 (let ((obj (car next
)))
812 (cond ((reciprocalp obj
)
813 (let ((expon (gen-quotients (exponent obj
)))
814 (mbase (gen-quotients (base obj
))))
817 (cond ((equal expon -
1)
818 (cond ((mtimesp mbase
) (cdr mbase
))
820 (t (ncons (make-expt mbase
(gen-negative expon
)))))))
822 (do ((seplist (cdr x
) (cdr seplist
)))
824 (let ((element (car seplist
)))
825 (or (reciprocalp element
)
826 (setq numerator
`(,.numerator
,element
))))))))
828 (let ((result (gen-quotients obj
)))
831 (do ((seplist (cdr x
) (cdr seplist
)))
833 (let ((element (car seplist
)))
834 (or (reciprocalp element
)
835 (setq numerator
`(,.numerator
,element
))))))
836 (and (or numerator denominator
(not (eq obj result
)))
837 (setq numerator
`(,.numerator
,result
)))))))))
839 `((mquotient) 1 ,(gen-quotients (let ((exp (exponent x
))
841 (cond ((equal -
1 exp
) mbase
)
842 (t (make-expt mbase
(gen-negative exp
))))))))
844 (do ((next (cdr x
) (cdr next
))
849 (let* ((obj (car next
))
850 (result (gen-quotients obj
)))
853 (setq new
(copy-to-pntr x next
)))
854 (and (or new
(not (eq obj result
)))
855 (setq new
`(,.new
,result
))))))))
857 (defun integer-gathering (x)
858 (do ((new x
(igcd-exponent-gather (integer-exponent-gather new
)))
860 ((eq new onew
) new
)))
862 (defun $gather_exponents
(x)
863 (do ((new (gen-quotients x
)
864 (fgcd-exponent-gather (floating-exponent-gather new
)))
866 ((eq new onew
) (integer-gathering new
))))