1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancments. ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; (c) Copyright 1982 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 (macsyma-module nisimp
)
15 ;;;programs for the LET LETSIMP LETRULES and REMLET commands
16 ;;;these programs use the names LETSIMPTREE and LETRULES on the
17 ;;;property list of atoms
18 ;;;except for the top level programs all program names have the prefix NIS
20 (declare-top (special nistree nisrules nisflag $ratexpand varlist $ratfac
))
22 (defmvar $letvarsimp nil
)
26 (defmvar $default_let_rule_package
'$default_let_rule_package
27 "The name of the default rule package used by `let' and `letsimp'")
29 (putprop '$default_let_rule_package
'let-rule-setter
'assign
)
31 (defmvar $current_let_rule_package
'$default_let_rule_package
32 "The name of the current rule package used by `let' and `letsimp'")
34 (putprop '$current_let_rule_package
'let-rule-setter
'assign
)
36 (defmvar $let_rule_packages
'((mlist) $default_let_rule_package
)
37 "The names of the various let rule simplification packages")
39 (putprop '$let_rule_packages
'let-rule-setter
'assign
)
41 (setq nisrules nil nistree nil
)
43 (defun let-rule-setter (var val
)
44 (cond ((eq var
'$default_let_rule_package
)
45 (merror (intl:gettext
"assignment: cannot assign to default_let_rule_package.")))
46 ((and (eq var
'$current_let_rule_package
)
47 (not (memalike val
(cdr $let_rule_packages
))))
48 (merror (intl:gettext
"assignment: ~M is not a rule package.") val
))
49 ((eq var
'$let_rule_packages
)
50 (merror (intl:gettext
"assignment: cannot assign to let_rule_packages.~%assignment: call 'let' to create let rule packages.")))))
52 (defmspec $let
(l) (setq l
(cdr l
))
53 (if (null (cdr l
)) (wna-err '$let
))
54 ;;LET([PATTERN,REPL,PRED,ARG1,...,ARGN],NAME)
55 (prog (pattern pat replacement treename text $ratfac
)
56 ;;LET(PATTERN,REPL,PRED,ARG1,...,ARGN)
58 (setq treename $current_let_rule_package
))
59 ((eq 'mlist
(caaar l
))
60 (setq treename
(cadr l
))
61 (if (not (symbolp treename
))
62 (improper-arg-err treename
'$let
))
64 (t (setq treename $current_let_rule_package
)))
65 (let ((nistree (mget treename
'letsimptree
))
66 (nisrules (mget treename
'letrules
)))
67 (setq pat
(strip-lineinfo (meval (car l
))))
68 (setq replacement
(cdr l
))
69 (setq pattern
(cond ((atom pat
) (list pat
))
70 ((eq (caar pat
) 'mtimes
)
73 (setq nistree
(nislet nistree pattern replacement
))
74 (cond (treename (mputprop treename
77 (add2lnc treename $let_rule_packages
)))
78 (nonsymchk (caddr l
) '$let
)
80 (append (list '(mtext) pat
'| --
> |
)
83 '#.
(intern (format nil
" ~A " 'where
))
84 (cons (list (caddr l
))
87 (setq nisrules
(append (list text
) nisrules
))
88 (cond (treename (mputprop treename
93 (defun nislet (tree list function
)
95 (setq permlist
(nispermutations list
))
96 step
(cond ((eq nil permlist
) (return tree
)))
97 (setq tree
(nistreebuilder tree
(car permlist
) function
))
98 (setq permlist
(cdr permlist
))
101 (defun nispermutations (llist)
103 ((null (cdr llist
)) (list llist
))
108 (nisaddon (car llist
)
109 (nispermutations (append a
(cdr llist
))))
111 (if (null (cdr llist
)) (return permlist
))
113 (setq llist
(cdr llist
))
116 (defun nisaddon (x llist
)
117 (if llist
(cons (cons x
(car llist
)) (nisaddon x
(cdr llist
)))))
119 (defun nistreebuilder (tree perm function
)
120 (cond ((null perm
) (cons (list function
) tree
))
122 (list (cons (car perm
)
123 (nistreebuilder nil
(cdr perm
) function
))))
124 ((equal (car perm
) (caar tree
))
127 (nistreebuilder (cdar tree
)
131 (nistreebuilder (cdr tree
)
135 (defun nisswcar (x y
)
138 (defun nisswcdr (x y
)
141 (defmspec $remlet
(x)
143 ;; REMLET(PROD,NAME) REMLET(PROD) REMLET() REMLET(FALSE,NAME)
144 (prog (pattern text treename
)
145 (cond ((cddr x
) (wna-err '$remlet
))
146 ((null (cdr x
)) (setq treename $current_let_rule_package
))
147 (t (setq treename
(cadr x
))
148 (if (not (symbolp treename
))
149 (improper-arg-err treename
'$remlet
))))
150 (setq pattern
(strip-lineinfo (meval (car x
))))
151 (when (or (not pattern
) (eq '$all pattern
))
152 (setq nisrules nil nistree nil
)
153 (unless (eq treename
'$default_let_rule_package
)
154 (setq $let_rule_packages
(delete treename $let_rule_packages
:count
1 :test
#'eq
)))
156 (setq nistree
(mget treename
'letsimptree
))
157 (if (setq text
(nisremlet pattern
)) (return text
))
160 (nistreelister (mget treename
'letrules
) pattern
))
162 a
(mputprop treename nistree
'letsimptree
)
163 (mputprop treename nisrules
'letrules
)
166 (defun nistreelister (llist pattern
)
168 a
(if (alike1 pattern
(cadar llist
)) (return (append x
(cdr llist
))))
169 (setq x
(append x
(list (car llist
))) llist
(cdr llist
))
172 (defun nisremlet (pat)
173 (prog (llist permlist x
)
174 (setq llist
(if (mtimesp pat
) (cdr pat
) (ncons pat
)))
175 (setq nisflag t x nistree
)
176 (setq permlist
(nispermutations llist
))
177 step
(when (null permlist
) (setq nistree x
) (return nil
))
178 (setq x
(nistreetrimmer (car permlist
) x
))
179 (if (null nisflag
) (merror (intl:gettext
"remlet: no rule found: ~M") pat
))
180 (setq permlist
(cdr permlist
))
183 (defun nistreetrimmer (perm tree
)
185 (cond ((null tree
) (setq nisflag nil
))
187 (setq nisflag
(caar tree
)) (cdr tree
))
188 (t (nisswcdr tree
(nistreetrimmer nil
(cdr tree
))))))
189 ((null tree
) (setq nisflag nil
))
190 ((equal (car perm
) (caar tree
))
192 (setq x
(nistreetrimmer (cdr perm
) (cdar tree
)))
193 (if (null x
) (return (cdr tree
)))
194 (return (nisswcar tree
(nisswcdr (car tree
) x
)))))
195 (t (nisswcdr tree
(nistreetrimmer perm
(cdr tree
))))))
197 (defmspec $letrules
(name)
198 (setq name
(cdr name
)) ;LETRULES(NAME)
199 (let ((treename (if name
(car name
) $current_let_rule_package
)))
200 (if (not (symbolp treename
)) (improper-arg-err treename
'$letrules
))
201 (setq nistree
(mget treename
'letsimptree
)
202 nisrules
(mget treename
'letrules
))
203 (apply #'$disp nisrules
)))
205 (defmspec $letsimp
(form) ;letsimp(expr,tree1,...,treen)
206 (setq form
(cdr form
))
207 (let* ((expr (strip-lineinfo (meval (pop form
))))
210 (progv (unless sw
'(varlist genvar
))
211 (unless sw
(list varlist genvar
))
212 (when (and sw
(member 'trunc
(cdar expr
) :test
#'eq
))
213 (setq expr
($taytorat expr
)))
214 (dolist (rulepackage (or form
(list $current_let_rule_package
))
215 (if sw
(ratf expr
) expr
))
216 (unless (symbolp rulepackage
)
217 (improper-arg-err rulepackage
'$letsimp
))
218 (when (setq nistree
(mget rulepackage
'letsimptree
))
219 ;; Whereas nisletsimp returns an expression in general
220 ;; representation, the original expr might be in CRE form.
221 ;; Regardless, we use ratf to make sure varlist and genvar
222 ;; know of expr's kernels.
223 (setq expr
(nisletsimp (if (atom expr
)
227 (defun nisletsimp (e)
230 ((or (and (atom e
) (setq x
(ncons e
)))
231 (and (eq (caar e
) 'mtimes
) (setq x
(cdr e
))))
232 (setq x
(nisnewlist x
))
233 (if x
(nisletsimp ($ratexpand
(cons '(mtimes) x
))) e
))
234 ((member (caar e
) '(mplus mequal mlist $matrix
) :test
#'eq
)
235 (cons (if (eq (caar e
) 'mplus
) '(mplus) (car e
))
236 (mapcar #'nisletsimp
(cdr e
))))
237 ((or (eq (caar e
) 'mrat
)
238 (and (eq (caar e
) 'mquotient
) (setq e
(ratf e
))))
240 (t ;; A kernel (= product of 1 element)
241 (setq x
(nisnewlist (ncons e
)))
242 (if x
(nisletsimp ($ratexpand
(cons '(mtimes) x
))) e
)))))
244 (defun nisletsimprat (e)
245 (let ((num (cadr e
)) (denom (cddr e
)) $ratexpand
)
246 (if $letvarsimp
(setq varlist
(mapcar #'nisletsimp varlist
)))
247 (let (($ratexpand t
))
248 ; Construct new CREs based on the numerator and denominator
249 ; of E and disrep them in the VARLIST and GENVAR context from
252 ; NISLETSIMP can change VARLIST and GENVAR, so the order of
253 ; the PDIS and NISLETSIMP forms matter here. PDISing and
254 ; NISLETSIMPing the numerator before moving on to the
255 ; denominator is not correct.
256 (let ((varlist (mrat-varlist e
))
257 (genvar (mrat-genvar e
)))
260 (setq num
(nisletsimp num
)
261 denom
(nisletsimp denom
)))
262 (setq e
(list '(mquotient) num denom
))
263 (if $letrat
(nisletsimp ($ratexpand e
)) e
)))
265 (defun nisnewlist (llist)
266 (let ((x (nissearch llist nistree nil
))) (if x
(nisreplace llist x
))))
268 (defun nissearch (x y z
)
270 ((nisinnernull y
) (nisfix (nisinnernull y
) z
))
272 (t (prog (xx yy path bind
)
275 b
(cond ((and (setq bind
(nismatch (car xx
)
282 (return (cons (car bind
) path
))))
286 (cond ((null yy
) (return nil
)))
289 (defun nisinnernull (x)
291 ((null (cdar x
)) (caar x
))
292 (t (nisinnernull (cdr x
)))))
294 (defun nisfix (funperd argasslist
)
295 (prog (function args bindings perd flag
)
296 (if (not argasslist
) (return (car funperd
)))
297 (setq argasslist
(nisnumberpicker argasslist
))
298 (setq args
(maplist 'caar argasslist
))
299 (setq bindings
(maplist 'cdar argasslist
))
300 (mbinding (args bindings
)
301 (setq function
(car funperd
))
302 (if (setq perd
(cdr funperd
))
303 (if (not (meval perd
)) (setq flag t
)))
304 (if (null flag
) (setq function
(meval function
))))
305 (return (if flag nil
(list function
)))))
307 (defun nisnumberpicker (x)
309 ((or (not (symbolp (caar x
)))
310 (kindp (caar x
) '$constant
))
311 ;; Skip over numbers and constants
312 (nisnumberpicker (cdr x
)))
313 (t (nisswcdr x
(nisnumberpicker (cdr x
))))))
315 (defun nismatch (a b c
)
317 (setq x
(nisextract a
))
318 (setq y
(nisextract b
))
321 (cond ((and (equal (car x
) (car y
))
322 (setq c
(nisargschecker (cadr x
)
325 (setq newexpt
(nisexpocheck (cddr x
)
328 (cond ((equal '(rat) (car newexpt
))
329 (return (cons (cons a
(nisbuild x newexpt
))
331 (t (return (cons (cons a
'(dummy 0 (0 0)))
334 (cond ((and (setq c
(nisargmatch (niskernel a
) (car y
) c
))
335 (setq newexpt
(nisexpocheck (cddr x
)
338 (cond ((equal '(rat) (car newexpt
))
339 (return (cons (cons a
(nisbuild x newexpt
))
341 (t (return (cons (cons a
'(dummy 0 (0 0)))
346 (if (mexptp a
) (cadr a
) a
))
348 (defun nisextract (x)
349 (cond ((or (atom x
) (eq (caar x
) 'rat
))
350 (cons x
(cons nil
1)))
351 ((eq 'mexpt
(caar x
))
352 (cond ((atom (cadr x
))
353 (cons (cadr x
) (cons nil
(caddr x
))))
354 (t (cons (if (member 'array
(cdaadr x
) :test
#'eq
)
355 (list (caaadr x
) 'array
)
357 (cons (cdadr x
) (caddr x
))))))
358 (t (cons (if (member 'array
(cdar x
) :test
#'eq
)
359 (list (caar x
) 'array
)
363 (defun nisargschecker (listargs treeargs argasslist
)
365 (cond ((and listargs treeargs
) (go check
))
366 ((or listargs treeargs
) (return nil
))
367 (t (return argasslist
)))
368 check
(setq c
(nisargmatch (car listargs
)
371 (cond (c (return (nisargschecker (cdr listargs
)
376 (defun nisexpocheck (listpower treepower argasslist
)
377 (prog (p q r s a b xx
)
378 (cond ((atom treepower
)
379 (cond ((numberp treepower
)
380 (prog2 (setq r treepower s
1) (go math
)))
381 (t (return (nisargmatch listpower
384 (setq r
(cadr treepower
) s
(caddr treepower
))
385 (if (not (numberp s
)) (return nil
))
386 math
(cond ((numberp listpower
) (setq p listpower q
1))
387 ((atom listpower
) (return nil
))
388 ((eq 'rat
(caar listpower
))
389 (setq p
(cadr listpower
) q
(caddr listpower
)))
391 (setq xx
(* (* q s
) (- (* p s
) (* q r
))))
392 (setq a
(< (* r s
) 0))
394 (cond ((or (not (or a b
)) (and a
(or b
(equal 0 xx
))))
395 (return (list '(rat) xx
(* q s
)))))
398 (defun nisargmatch (x y c
)
401 up
(if (null w
) (go down
))
402 (cond ((eq (caar w
) y
)
403 (cond ((alike1 (cdar w
) x
) (return c
))
407 down
(setq w
(mget y
'matchdeclare
))
408 (cond ((null w
) (if (equal x y
) (go out
) (return nil
)))
409 ((member (car w
) '($true t
) :test
#'eq
) (go out
))
411 (meval (cons (ncons (car w
))
412 (append (cdr w
) (list x
)))))
414 ((and (not (atom (car w
)))
415 (not (atom (caar w
)))
417 ; If we arrive here, (CAR W) is a Maxima expression like ((FOO) ...)
418 ; If (CAR W) is a Maxima lambda expression, evaluate it via MFUNCALL.
419 ; Otherwise, append X and call MEVAL.
420 ; Note that "otherwise" includes Maxima lambda expressions with missing arguments;
421 ; in that case the expression is ((MQAPPLY) ((LAMBDA) ...)) and MEVAL is the way to go.
422 (if (eq (caaar w
) 'lambda
)
424 (meval (append (car w
) (list x
)))))
427 out
(return (cons (cons y x
) c
))))
429 (defun nisbuild (x newexpt
)
432 (cons (if (symbolp (car x
)) (ncons (car x
)) (car x
))
437 (defun nisreplace (llist asslist
)
438 (cond ((eq (cdr asslist
) nil
) (cons (car asslist
) llist
))
439 ((equal (car llist
) (caar asslist
))
440 (cond ((equal 0 (cadar (cdddar asslist
)))
441 (nisreplace (cdr llist
) (cdr asslist
)))
442 (t (cons (cdar asslist
)
443 (nisreplace (cdr llist
) (cdr asslist
))))))
444 (t (cons (car llist
) (nisreplace (cdr llist
) asslist
)))))