2 Copyright
2006 by Barton Willis
4 This is free software
; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
,
6 http
://www.gnu.org
/copyleft
/gpl.html.
8 This software has NO WARRANTY
, not even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 Usage
: The function
'opsubst
' is similar to the function
'subst
', except that
12 'opsubst
' only makes substitutions for the operators in an expression. Specifically
,
14 opsubst
(f,g
,e
) --
> When
'f
' is an operator in the expression e
, substitute
'g
'
15 for
'f
' in the expression
'e
'.
16 opsubst
(g=f
,e
) --
> opsubst
(f,g
,e
).
18 opsubst
([g1
=f1
, g2
=f2
, ...
, gn
=fn
],e
) --
> opsubst
([g2
=f2
,...
,gn
=fn
], opsubst
(f1=f1
, e
)).
22 (%i1
) opsubst
(f,g
,g
(g(x)));
24 (%i2
) opsubst
(f,g
,g
(g));
26 (%i3
) opsubst
(f,g
[x],g[x](z));
28 (%i4
) opsubst
(g[x],f, f(z));
30 (%i5
) opsubst
(tan, sin
, sin
(sin));
32 (%i6
) opsubst
([f
=g
,g
=h
],f
(x));
35 To determine the operator
, 'opsubst
' sets
'inflag
' to true. This means
36 'opsubst
' substitutes for the internal
, not the displayed
, operator.
37 Since Maxima does not internally use the unary negation or division
38 operators
, substituting for these operators will not work
; examples:
40 (%i1
) opsubst
("+","-",a-b
);
42 (%i2
) opsubst
("f","-",-a
);
44 (%i3
) opsubst
("^^","/",a
/b
);
47 The internal representation of -a
*b is
*(-1,a
,b
); thus
49 (%i4
) opsubst
("[","*", -a
*b
);
52 If opsubst did not locally set
'inflag
' to true
, we
'd have
:
54 (%i1
) opsubst
("[","*", -a
*b
), listarith
: true
;
56 (%i2
) opsubst
("[","*", -a
*b
), listarith
: false
;
59 So opsubst
("*","[", opsubst
("[","*", -a
*b
)) # -a
*b. There is
60 nothing wrong with this
; however, With 'inflag' set to true,
61 we have
(regardless of the value of listarith
)
63 (%i1
) opsubst
("[","*", -a
*b
);
65 (%i2
) opsubst
("*","[",%
);
68 To me
, it seems that it is better to substitute for the internal
69 rather than the displayed operator. But do not be mislead by this
72 opsubst
(f,g
,opsubst
(g,f
,e
)) = e
76 When either the first or second arguments of
'opsubst
' are not Maxima
77 symbols
, generally some other function will signal an error
; for
80 (%i5
) opsubst
(a+b
,f
, f
(x));
81 Improper name or value in functional position
:b
+a
83 However
, the first two arguments to
'opsubst
' can be
86 (%i6
) opsubst
(g[5],f, f(x));
91 ;; Applies op to args and simplifies the result. The function my-take isn't supposed
92 ;; to evaluate args. I think the maxima 'take' macro doesn't handle subscripted
93 ;; operators correctly--this function my-take should be OK with subscripted operators.
94 ;; (Also the take macro special-cases a few operators for the simplification function. Yeech.)
96 (defun my-take (op args
)
97 (simplify (if (and (consp op
) (member 'array
(car op
))) `((mqapply) ,op
,@args
) `((,op
) ,@args
))))
99 (defun $opsubst
(&rest q
)
101 (cond ((= 3 (length q
)) (apply 'op-subst q
))
104 (setq q
(if ($listp
(first q
)) (margs (first q
)) (list (first q
))))
106 (if (op-equalp qi
'mequal
) (setq e
(op-subst ($rhs qi
) ($lhs qi
) e
))
107 (merror "Expected an expression of the form `a = b'; instead found ~:M" qi
))))
108 (t (wna-err '$opsubst
)))))
110 ;; If op is a string, verbify it; otherwise, return op. Without this transformation,
111 ;; things like opsubst("[",f, f(a,b,c)) would fail. Notice that subst(f[1] = "[", f[1](1,2,3))
112 ;; doesn't work correctly.
114 (defun verbify-string (op)
115 (if (stringp op
) ($verbify op
) op
))
117 ;; If op is a symbol, verbify it; otherwise, return op.
119 (defun safe-verbify (op)
120 (if (symbolp op
) ($verbify op
) op
))
122 (defun op-subst (f g e
)
123 (setq f
(verbify-string f
))
124 (setq g
(verbify-string g
))
128 (my-take (if (like (safe-verbify g
) (safe-verbify (mop e
))) f
(mop e
))
129 (mapcar #'(lambda (s) (op-subst f g s
)) (margs ($args e
)))))))
131 ;; If prd(e) evaluates to true, do the substitution opsubst(id, e). The
132 ;; first argument should be an equation of the form symbol = symbol | lambda form
133 ;; or a list of such equations.
135 (defun $opsubstif
(id prd e
)
136 (setq id
(if ($listp id
) (margs id
) (list id
)))
138 (if (op-equalp qi
'mequal
) (setq e
(op-subst-if (verbify-string ($rhs qi
))
139 (verbify-string ($lhs qi
)) prd e
))
140 (merror "Expected an expression of the form `a = b'; instead found ~:M" qi
)))
143 (defun op-subst-if (fn fo prd e
)
144 (let (($inflag t
) ($prederror nil
))
145 (cond (($mapatom e
) e
)
147 (my-take (if (and (like (safe-verbify fo
) (safe-verbify (mop e
)))
148 (eq t
(mevalp (mfuncall prd
($args e
))))) fn
(mop e
))
149 (mapcar #'(lambda (s) (op-subst-if fn fo prd s
)) (margs ($args e
))))))))
151 ;; Return a list of all the arguments to the operator 'op.' Each argument is
152 ;; a list (what 'args' would return). Examples:
154 ;; (%i1) gatherargs(f(x) + f(y),'f);
157 ;; In the expression 42 + f(f(x)), both x and f(x) are arguments to f; thus
159 ;; (%i2) gatherargs(42 + f(f(x)),'f);
160 ;; (%o2) [[f(x)],[x]]
162 ;; (%i3) gatherargs(f^2 + %pi,'f);
166 (defun $gatherargs
(e op
)
167 `((mlist) ,@(gatherargs e op
)))
169 (defun gatherargs (e op
)
171 (append (if (op-equalp e op
($nounify op
) ($verbify op
)) `(((mlist) ,@(margs e
))))
172 (mapcan #'(lambda (s) (gatherargs s op
)) (margs e
)))))
174 (defun $gatherops
(e)
175 ($setify
`((mlist) ,@(gatherops e
))))
178 (if ($mapatom e
) nil
(cons ($op e
) (mapcan #'gatherops
(margs e
)))))