File: opsubst.lisp

package info (click to toggle)
maxima-sage 5.45.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid, trixie
  • size: 113,788 kB
  • sloc: lisp: 440,833; fortran: 14,665; perl: 14,369; tcl: 10,997; sh: 4,475; makefile: 2,520; ansic: 447; python: 262; xml: 59; awk: 37; sed: 17
file content (182 lines) | stat: -rw-r--r-- 5,719 bytes parent folder | download | duplicates (14)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#|
  Copyright 2006 by Barton Willis

  This is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License,
  http://www.gnu.org/copyleft/gpl.html.

 This software has NO WARRANTY, not even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Usage: The function 'opsubst' is similar to the function 'subst', except that
'opsubst' only makes substitutions for the operators in an expression. Specifically,

 opsubst(f,g,e) --> When 'f' is an operator in the expression e, substitute 'g' 
                    for 'f' in the expression 'e'. 
 opsubst(g=f,e) --> opsubst(f,g,e).
 opsubst([],e) --> e.
 opsubst([g1=f1, g2=f2, ..., gn=fn],e) --> opsubst([g2=f2,...,gn=fn], opsubst(f1=f1, e)).

 Examples:

(%i1) opsubst(f,g,g(g(x)));
(%o1) f(f(x))
(%i2) opsubst(f,g,g(g));
(%o2) f(g)
(%i3) opsubst(f,g[x],g[x](z));
(%o3) f(z)
(%i4) opsubst(g[x],f, f(z));
(%o4) g[x](z)
(%i5) opsubst(tan, sin, sin(sin));
(%o5) tan(SIN)
(%i6) opsubst([f=g,g=h],f(x));
(%o6) h(x)

To determine the operator, 'opsubst' sets 'inflag' to true. This means
'opsubst' substitutes for the internal, not the displayed, operator.
Since Maxima does not internally use the unary negation or division
operators, substituting for these operators will not work; examples:

(%i1) opsubst("+","-",a-b);
(%o1) a-b
(%i2) opsubst("f","-",-a);
(%o2) -a
(%i3) opsubst("^^","/",a/b);
(%o3) a/b

The internal representation of -a*b is *(-1,a,b); thus

(%i4) opsubst("[","*", -a*b);
(%o4) [-1,a,b]

If opsubst did not locally set 'inflag' to true, we'd have:

(%i1) opsubst("[","*", -a*b), listarith : true;
(%o1) [-a,-b]
(%i2) opsubst("[","*", -a*b), listarith : false;
(%o2) -[a,b]

So opsubst("*","[", opsubst("[","*", -a*b)) # -a*b. There is
nothing wrong with this; however, With 'inflag' set to true, 
we have (regardless of the value of listarith)

(%i1) opsubst("[","*", -a*b);
(%o1) [-1,a,b]
(%i2) opsubst("*","[",%);
(%o2) -a*b

To me, it seems that it is better to substitute for the internal
rather than the displayed operator. But do not be mislead by this
example, the equation
 
   opsubst(f,g,opsubst(g,f,e)) = e

is not an identity.

When either the first or second arguments of 'opsubst' are not Maxima
symbols, generally some other function will signal an error; for
example

(%i5) opsubst(a+b,f, f(x));
Improper name or value in functional position:b+a

However, the first two arguments to 'opsubst' can be 
subscripted:

(%i6) opsubst(g[5],f, f(x));
(%o6) g[5](x)

|#

;; Applies op to args and simplifies the result. The function my-take isn't supposed
;; to evaluate args. I think the maxima 'take' macro doesn't handle subscripted 
;; operators correctly--this function my-take should be OK with subscripted operators.
;; (Also the take macro special-cases a few operators for the simplification function. Yeech.)

(defun my-take (op args)
  (simplify (if (and (consp op) (member 'array (car op))) `((mqapply) ,op ,@args) `((,op) ,@args))))

(defun $opsubst (&rest q)
  (let ((e))
    (cond ((= 3 (length q)) (apply 'op-subst q))
	  ((= 2 (length q))
	   (setq e (second q))
	   (setq q (if ($listp (first q)) (margs (first q)) (list (first q))))
	   (dolist (qi q e)
	     (if (op-equalp qi 'mequal) (setq e (op-subst ($rhs qi) ($lhs qi) e))
	       (merror "Expected an expression of the form `a = b'; instead found ~:M" qi))))
	  (t (wna-err '$opsubst)))))

;; If op is a string, verbify it; otherwise, return op. Without this transformation,
;; things like opsubst("[",f, f(a,b,c)) would fail. Notice that subst(f[1] = "[", f[1](1,2,3))
;; doesn't work correctly.

(defun verbify-string (op)
  (if (stringp op) ($verbify op) op))

;; If op is a symbol, verbify it; otherwise, return op.

(defun safe-verbify (op)
  (if (symbolp op) ($verbify op) op))

(defun op-subst (f g e)
  (setq f (verbify-string f))
  (setq g (verbify-string g))

  (let (($inflag t))
    (if ($mapatom e) e
      (my-take (if (like (safe-verbify g) (safe-verbify (mop e))) f (mop e)) 
	       (mapcar #'(lambda (s) (op-subst f g s)) (margs ($args e)))))))

;; If prd(e) evaluates to true, do the substitution opsubst(id, e). The
;; first argument should be an equation of the form symbol = symbol | lambda form
;; or a list of such equations.

(defun $opsubstif (id prd e)
  (setq id (if ($listp id) (margs id) (list id)))
  (dolist (qi id)
    (if (op-equalp qi 'mequal) (setq e (op-subst-if (verbify-string ($rhs qi))
						    (verbify-string ($lhs qi)) prd e))
      (merror "Expected an expression of the form `a = b'; instead found ~:M" qi)))
  e)
        	  
(defun op-subst-if (fn fo prd e)
  (let (($inflag t) ($prederror nil))
    (cond (($mapatom e) e)
	  (t
	   (my-take (if (and (like (safe-verbify fo) (safe-verbify (mop e)))
			     (eq t (mevalp (mfuncall prd ($args e))))) fn (mop e))
		    (mapcar #'(lambda (s) (op-subst-if fn fo prd s)) (margs ($args e))))))))
	  	   	  
;; Return a list of all the arguments to the operator 'op.' Each argument is
;; a list (what 'args' would return).  Examples:

;; (%i1) gatherargs(f(x) + f(y),'f);
;; (%o1) [[x],[y]]

;; In the expression 42 + f(f(x)), both x and f(x) are arguments to f; thus

;; (%i2) gatherargs(42 + f(f(x)),'f);
;; (%o2) [[f(x)],[x]]

;; (%i3) gatherargs(f^2 + %pi,'f);
;; (%o3) []

	   
(defun $gatherargs (e op)
  `((mlist) ,@(gatherargs e op)))

(defun gatherargs (e op)
  (if ($mapatom e) nil
    (append (if (op-equalp e op ($nounify op) ($verbify op)) `(((mlist) ,@(margs e))))
	    (mapcan #'(lambda (s) (gatherargs s op)) (margs e)))))
	 	  
(defun $gatherops (e)
  ($setify `((mlist) ,@(gatherops e))))

(defun gatherops (e)
  (if ($mapatom e) nil (cons ($op e) (mapcan #'gatherops (margs e)))))