Switch to recommended form of GPLv3 permissions notice.
[bpt/emacs.git] / lisp / calc / calc-rewr.el
CommitLineData
3132f345
CW
1;;; calc-rewr.el --- rewriting functions for Calc
2
58ba2f8f 3;; Copyright (C) 1990, 1991, 1992, 1993, 2001, 2002, 2003, 2004,
8b72699e 4;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
3132f345
CW
5
6;; Author: David Gillespie <daveg@synaptics.com>
e8fff8ed 7;; Maintainer: Jay Belanger <jay.p.belanger@gmail.com>
136211a9
EZ
8
9;; This file is part of GNU Emacs.
10
662c9c64 11;; GNU Emacs is free software: you can redistribute it and/or modify
7c671b23 12;; it under the terms of the GNU General Public License as published by
662c9c64
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
7c671b23 15
136211a9 16;; GNU Emacs is distributed in the hope that it will be useful,
7c671b23
GM
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
662c9c64 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
136211a9 23
3132f345 24;;; Commentary:
136211a9 25
3132f345 26;;; Code:
136211a9
EZ
27
28;; This file is autoloaded from calc-ext.el.
136211a9 29
a2470ec9 30(require 'calc-ext)
136211a9
EZ
31(require 'calc-macs)
32
3132f345 33(defvar math-rewrite-default-iters 100)
40ead937
JB
34
35;; The variable calc-rewr-sel is local to calc-rewrite-selection and
36;; calc-rewrite, but is used by calc-locate-selection-marker.
37(defvar calc-rewr-sel)
38
136211a9
EZ
39(defun calc-rewrite-selection (rules-str &optional many prefix)
40 (interactive "sRewrite rule(s): \np")
41 (calc-slow-wrapper
42 (calc-preserve-point)
43 (let* ((num (max 1 (calc-locate-cursor-element (point))))
44 (reselect t)
45 (pop-rules nil)
40ead937 46 rules
136211a9
EZ
47 (entry (calc-top num 'entry))
48 (expr (car entry))
40ead937 49 (calc-rewr-sel (calc-auto-selection entry))
136211a9
EZ
50 (math-rewrite-selections t)
51 (math-rewrite-default-iters 1))
52 (if (or (null rules-str) (equal rules-str "") (equal rules-str "$"))
53 (if (= num 1)
3132f345 54 (error "Can't use same stack entry for formula and rules")
136211a9
EZ
55 (setq rules (calc-top-n 1 t)
56 pop-rules t))
57 (setq rules (if (stringp rules-str)
58 (math-read-exprs rules-str) rules-str))
59 (if (eq (car-safe rules) 'error)
60 (error "Bad format in expression: %s" (nth 1 rules)))
61 (if (= (length rules) 1)
62 (setq rules (car rules))
63 (setq rules (cons 'vec rules)))
64 (or (memq (car-safe rules) '(vec var calcFunc-assign
65 calcFunc-condition))
66 (let ((rhs (math-read-expr
67 (read-string (concat "Rewrite from: " rules-str
68 " to: ")))))
69 (if (eq (car-safe rhs) 'error)
70 (error "Bad format in expression: %s" (nth 1 rhs)))
71 (setq rules (list 'calcFunc-assign rules rhs))))
72 (or (eq (car-safe rules) 'var)
73 (calc-record rules "rule")))
74 (if (eq many 0)
75 (setq many '(var inf var-inf))
76 (if many (setq many (prefix-numeric-value many))))
40ead937 77 (if calc-rewr-sel
136211a9 78 (setq expr (calc-replace-sub-formula (car entry)
40ead937
JB
79 calc-rewr-sel
80 (list 'calcFunc-select calc-rewr-sel)))
136211a9
EZ
81 (setq expr (car entry)
82 reselect nil
83 math-rewrite-selections nil))
84 (setq expr (calc-encase-atoms
85 (calc-normalize
86 (math-rewrite
87 (calc-normalize expr)
88 rules many)))
40ead937 89 calc-rewr-sel nil
136211a9 90 expr (calc-locate-select-marker expr))
40ead937 91 (or (consp calc-rewr-sel) (setq calc-rewr-sel nil))
136211a9
EZ
92 (if pop-rules (calc-pop-stack 1))
93 (calc-pop-push-record-list 1 (or prefix "rwrt") (list expr)
94 (- num (if pop-rules 1 0))
40ead937 95 (list (and reselect calc-rewr-sel))))
bf77c646 96 (calc-handle-whys)))
136211a9 97
40ead937 98(defun calc-locate-select-marker (expr)
136211a9
EZ
99 (if (Math-primp expr)
100 expr
101 (if (and (eq (car expr) 'calcFunc-select)
102 (= (length expr) 2))
103 (progn
40ead937 104 (setq calc-rewr-sel (if calc-rewr-sel t (nth 1 expr)))
136211a9
EZ
105 (nth 1 expr))
106 (cons (car expr)
bf77c646 107 (mapcar 'calc-locate-select-marker (cdr expr))))))
136211a9
EZ
108
109
110
111(defun calc-rewrite (rules-str many)
112 (interactive "sRewrite rule(s): \nP")
113 (calc-slow-wrapper
114 (let (n rules expr)
115 (if (or (null rules-str) (equal rules-str "") (equal rules-str "$"))
116 (setq expr (calc-top-n 2)
117 rules (calc-top-n 1 t)
118 n 2)
119 (setq rules (if (stringp rules-str)
120 (math-read-exprs rules-str) rules-str))
121 (if (eq (car-safe rules) 'error)
122 (error "Bad format in expression: %s" (nth 1 rules)))
123 (if (= (length rules) 1)
124 (setq rules (car rules))
125 (setq rules (cons 'vec rules)))
126 (or (memq (car-safe rules) '(vec var calcFunc-assign
127 calcFunc-condition))
128 (let ((rhs (math-read-expr
129 (read-string (concat "Rewrite from: " rules-str
130 " to: ")))))
131 (if (eq (car-safe rhs) 'error)
132 (error "Bad format in expression: %s" (nth 1 rhs)))
133 (setq rules (list 'calcFunc-assign rules rhs))))
134 (or (eq (car-safe rules) 'var)
135 (calc-record rules "rule"))
136 (setq expr (calc-top-n 1)
137 n 1))
138 (if (eq many 0)
139 (setq many '(var inf var-inf))
140 (if many (setq many (prefix-numeric-value many))))
141 (setq expr (calc-normalize (math-rewrite expr rules many)))
40ead937 142 (let (calc-rewr-sel)
136211a9
EZ
143 (setq expr (calc-locate-select-marker expr)))
144 (calc-pop-push-record-list n "rwrt" (list expr)))
bf77c646 145 (calc-handle-whys)))
136211a9 146
8cb77f98
JB
147(defun calc-match (pat &optional interactive)
148 (interactive "sPattern: \np")
136211a9
EZ
149 (calc-slow-wrapper
150 (let (n expr)
151 (if (or (null pat) (equal pat "") (equal pat "$"))
152 (setq expr (calc-top-n 2)
153 pat (calc-top-n 1)
154 n 2)
136211a9
EZ
155 (setq pat (if (stringp pat) (math-read-expr pat) pat))
156 (if (eq (car-safe pat) 'error)
157 (error "Bad format in expression: %s" (nth 1 pat)))
158 (if (not (eq (car-safe pat) 'var))
159 (calc-record pat "pat"))
160 (setq expr (calc-top-n 1)
161 n 1))
162 (or (math-vectorp expr) (error "Argument must be a vector"))
163 (if (calc-is-inverse)
164 (calc-enter-result n "mtcn" (math-match-patterns pat expr t))
bf77c646 165 (calc-enter-result n "mtch" (math-match-patterns pat expr nil))))))
136211a9
EZ
166
167
40ead937
JB
168(defvar math-mt-many)
169
170;; The variable math-rewrite-whole-expr is local to math-rewrite,
171;; but is used by math-rewrite-phase
172(defvar math-rewrite-whole-expr)
173
174(defun math-rewrite (math-rewrite-whole-expr rules &optional math-mt-many)
175 (let* ((crules (math-compile-rewrites rules))
176 (heads (math-rewrite-heads math-rewrite-whole-expr))
177 (trace-buffer (get-buffer "*Trace*"))
178 (calc-display-just 'center)
179 (calc-display-origin 39)
180 (calc-line-breaking 78)
181 (calc-line-numbering nil)
182 (calc-show-selections t)
183 (calc-why nil)
184 (math-mt-func (function
185 (lambda (x)
186 (let ((result (math-apply-rewrites x (cdr crules)
187 heads crules)))
188 (if result
189 (progn
190 (if trace-buffer
191 (let ((fmt (math-format-stack-value
192 (list result nil nil))))
193 (save-excursion
194 (set-buffer trace-buffer)
195 (insert "\nrewrite to\n" fmt "\n"))))
196 (setq heads (math-rewrite-heads result heads t))))
197 result)))))
136211a9 198 (if trace-buffer
40ead937 199 (let ((fmt (math-format-stack-value (list math-rewrite-whole-expr nil nil))))
136211a9
EZ
200 (save-excursion
201 (set-buffer trace-buffer)
202 (setq truncate-lines t)
203 (goto-char (point-max))
204 (insert "\n\nBegin rewriting\n" fmt "\n"))))
ce037856 205 (or math-mt-many (setq math-mt-many (or (nth 1 (car crules))
136211a9 206 math-rewrite-default-iters)))
ce037856
JB
207 (if (equal math-mt-many '(var inf var-inf)) (setq math-mt-many 1000000))
208 (if (equal math-mt-many '(neg (var inf var-inf))) (setq math-mt-many -1000000))
136211a9
EZ
209 (math-rewrite-phase (nth 3 (car crules)))
210 (if trace-buffer
40ead937 211 (let ((fmt (math-format-stack-value (list math-rewrite-whole-expr nil nil))))
136211a9
EZ
212 (save-excursion
213 (set-buffer trace-buffer)
214 (insert "\nDone rewriting"
ce037856 215 (if (= math-mt-many 0) " (reached iteration limit)" "")
136211a9 216 ":\n" fmt "\n"))))
40ead937 217 math-rewrite-whole-expr))
136211a9
EZ
218
219(defun math-rewrite-phase (sched)
ce037856 220 (while (and sched (/= math-mt-many 0))
136211a9 221 (if (listp (car sched))
40ead937 222 (while (let ((save-expr math-rewrite-whole-expr))
136211a9 223 (math-rewrite-phase (car sched))
40ead937 224 (not (equal math-rewrite-whole-expr save-expr))))
136211a9
EZ
225 (if (symbolp (car sched))
226 (progn
40ead937
JB
227 (setq math-rewrite-whole-expr
228 (math-normalize (list (car sched) math-rewrite-whole-expr)))
136211a9
EZ
229 (if trace-buffer
230 (let ((fmt (math-format-stack-value
40ead937 231 (list math-rewrite-whole-expr nil nil))))
136211a9
EZ
232 (save-excursion
233 (set-buffer trace-buffer)
234 (insert "\ncall "
235 (substring (symbol-name (car sched)) 9)
236 ":\n" fmt "\n")))))
237 (let ((math-rewrite-phase (car sched)))
238 (if trace-buffer
239 (save-excursion
240 (set-buffer trace-buffer)
241 (insert (format "\n(Phase %d)\n" math-rewrite-phase))))
40ead937
JB
242 (while (let ((save-expr math-rewrite-whole-expr))
243 (setq math-rewrite-whole-expr (math-normalize
244 (math-map-tree-rec math-rewrite-whole-expr)))
245 (not (equal math-rewrite-whole-expr save-expr)))))))
bf77c646 246 (setq sched (cdr sched))))
136211a9
EZ
247
248(defun calcFunc-rewrite (expr rules &optional many)
249 (or (null many) (integerp many)
250 (equal many '(var inf var-inf)) (equal many '(neg (var inf var-inf)))
251 (math-reject-arg many 'fixnump))
252 (condition-case err
253 (math-rewrite expr rules (or many 1))
bf77c646 254 (error (math-reject-arg rules (nth 1 err)))))
136211a9
EZ
255
256(defun calcFunc-match (pat vec)
257 (or (math-vectorp vec) (math-reject-arg vec 'vectorp))
258 (condition-case err
259 (math-match-patterns pat vec nil)
bf77c646 260 (error (math-reject-arg pat (nth 1 err)))))
136211a9
EZ
261
262(defun calcFunc-matchnot (pat vec)
263 (or (math-vectorp vec) (math-reject-arg vec 'vectorp))
264 (condition-case err
265 (math-match-patterns pat vec t)
bf77c646 266 (error (math-reject-arg pat (nth 1 err)))))
136211a9
EZ
267
268(defun math-match-patterns (pat vec &optional not-flag)
269 (let ((newvec nil)
270 (crules (math-compile-patterns pat)))
271 (while (setq vec (cdr vec))
272 (if (eq (not (math-apply-rewrites (car vec) crules))
273 not-flag)
274 (setq newvec (cons (car vec) newvec))))
bf77c646 275 (cons 'vec (nreverse newvec))))
136211a9
EZ
276
277(defun calcFunc-matches (expr pat)
278 (condition-case err
279 (if (math-apply-rewrites expr (math-compile-patterns pat))
280 1
281 0)
bf77c646 282 (error (math-reject-arg pat (nth 1 err)))))
136211a9
EZ
283
284(defun calcFunc-vmatches (expr pat)
285 (condition-case err
286 (or (math-apply-rewrites expr (math-compile-patterns pat))
287 0)
bf77c646 288 (error (math-reject-arg pat (nth 1 err)))))
136211a9
EZ
289
290
291
292;;; A compiled rule set is an a-list of entries whose cars are functors,
293;;; and whose cdrs are lists of rules. If there are rules with no
294;;; well-defined head functor, they are included on all lists and also
295;;; on an extra list whose car is nil.
296;;;
297;;; The first entry in the a-list is of the form (schedule A B C ...).
298;;;
299;;; Rule list entries take the form (regs prog head phases), where:
300;;;
301;;; regs is a vector of match registers.
302;;;
303;;; prog is a match program (see below).
304;;;
305;;; head is a rare function name appearing in the rule body (but not the
306;;; head of the whole rule), or nil if none.
307;;;
308;;; phases is a list of phase numbers for which the rule is enabled.
309;;;
310;;; A match program is a list of match instructions.
311;;;
312;;; In the following, "part" is a register number that contains the
313;;; subexpression to be operated on.
314;;;
315;;; Register 0 is the whole expression being matched. The others are
316;;; meta-variables in the pattern, temporaries used for matching and
317;;; backtracking, and constant expressions.
318;;;
319;;; (same part reg)
320;;; The selected part must be math-equal to the contents of "reg".
321;;;
322;;; (same-neg part reg)
323;;; The selected part must be math-equal to the negative of "reg".
324;;;
325;;; (copy part reg)
326;;; The selected part is copied into "reg". (Rarely used.)
327;;;
328;;; (copy-neg part reg)
329;;; The negative of the selected part is copied into "reg".
330;;;
331;;; (integer part)
332;;; The selected part must be an integer.
333;;;
334;;; (real part)
335;;; The selected part must be a real.
336;;;
337;;; (constant part)
338;;; The selected part must be a constant.
339;;;
340;;; (negative part)
341;;; The selected part must "look" negative.
342;;;
343;;; (rel part op reg)
344;;; The selected part must satisfy "part op reg", where "op"
345;;; is one of the 6 relational ops, and "reg" is a register.
346;;;
347;;; (mod part modulo value)
348;;; The selected part must satisfy "part % modulo = value", where
349;;; "modulo" and "value" are constants.
350;;;
351;;; (func part head reg1 reg2 ... regn)
352;;; The selected part must be an n-ary call to function "head".
353;;; The arguments are stored in "reg1" through "regn".
354;;;
355;;; (func-def part head defs reg1 reg2 ... regn)
356;;; The selected part must be an n-ary call to function "head".
357;;; "Defs" is a list of value/register number pairs for default args.
358;;; If a match, assign default values to registers and then skip
359;;; immediately over any following "func-def" instructions and
360;;; the following "func" instruction. If wrong number of arguments,
361;;; proceed to the following "func-def" or "func" instruction.
362;;;
363;;; (func-opt part head defs reg1)
364;;; Like func-def with "n=1", except that if the selected part is
365;;; not a call to "head", then the part itself successfully matches
366;;; "reg1" (and the defaults are assigned).
367;;;
368;;; (try part heads mark reg1 [def])
369;;; The selected part must be a function of the correct type which is
370;;; associative and/or commutative. "Heads" is a list of acceptable
371;;; types. An initial assignment of arguments to "reg1" is tried.
372;;; If the program later fails, it backtracks to this instruction
373;;; and tries other assignments of arguments to "reg1".
374;;; If "def" exists and normal matching fails, backtrack and assign
375;;; "part" to "reg1", and "def" to "reg2" in the following "try2".
376;;; The "mark" is a vector of size 5; only "mark[3-4]" are initialized.
377;;; "mark[0]" points to the argument list; "mark[1]" points to the
378;;; current argument; "mark[2]" is 0 if there are two arguments,
379;;; 1 if reg1 is matching single arguments, 2 if reg2 is matching
380;;; single arguments (a+b+c+d is never split as (a+b)+(c+d)), or
381;;; 3 if reg2 is matching "def"; "mark[3]" is 0 if the function must
382;;; have two arguments, 1 if phase-2 can be skipped, 2 if full
383;;; backtracking is necessary; "mark[4]" is t if the arguments have
384;;; been switched from the order given in the original pattern.
385;;;
386;;; (try2 try reg2)
387;;; Every "try" will be followed by a "try2" whose "try" field is
388;;; a pointer to the corresponding "try". The arguments which were
389;;; not stored in "reg1" by that "try" are now stored in "reg2".
390;;;
391;;; (alt instr nil mark)
392;;; Basic backtracking. Execute the instruction sequence "instr".
393;;; If this fails, back up and execute following the "alt" instruction.
394;;; The "mark" must be the vector "[nil nil 4]". The "instr" sequence
395;;; should execute "end-alt" at the end.
396;;;
397;;; (end-alt ptr)
398;;; Register success of the first alternative of a previous "alt".
399;;; "Ptr" is a pointer to the next instruction following that "alt".
400;;;
401;;; (apply part reg1 reg2)
402;;; The selected part must be a function call. The functor
403;;; (as a variable name) is stored in "reg1"; the arguments
404;;; (as a vector) are stored in "reg2".
405;;;
406;;; (cons part reg1 reg2)
407;;; The selected part must be a nonempty vector. The first element
408;;; of the vector is stored in "reg1"; the rest of the vector
409;;; (as another vector) is stored in "reg2".
410;;;
411;;; (rcons part reg1 reg2)
412;;; The selected part must be a nonempty vector. The last element
413;;; of the vector is stored in "reg2"; the rest of the vector
414;;; (as another vector) is stored in "reg1".
415;;;
416;;; (select part reg)
417;;; If the selected part is a unary call to function "select", its
418;;; argument is stored in "reg"; otherwise (provided this is an `a r'
419;;; and not a `g r' command) the selected part is stored in "reg".
420;;;
421;;; (cond expr)
422;;; The "expr", with registers substituted, must simplify to
423;;; a non-zero value.
424;;;
425;;; (let reg expr)
426;;; Evaluate "expr" and store the result in "reg". Always succeeds.
427;;;
428;;; (done rhs remember)
429;;; Rewrite the expression to "rhs", with register substituted.
430;;; Normalize; if the result is different from the original
431;;; expression, the match has succeeded. This is the last
432;;; instruction of every program. If "remember" is non-nil,
433;;; record the result of the match as a new literal rule.
434
435
436;;; Pseudo-functions related to rewrites:
437;;;
438;;; In patterns: quote, plain, condition, opt, apply, cons, select
439;;;
440;;; In righthand sides: quote, plain, eval, evalsimp, evalextsimp,
441;;; apply, cons, select
442;;;
443;;; In conditions: let + same as for righthand sides
444
445;;; Some optimizations that would be nice to have:
446;;;
447;;; * Merge registers with disjoint lifetimes.
448;;; * Merge constant registers with equivalent values.
449;;;
450;;; * If an argument of a commutative op math-depends neither on the
451;;; rest of the pattern nor on any of the conditions, then no backtracking
452;;; should be done for that argument. (This won't apply to very many
453;;; cases.)
454;;;
455;;; * If top functor is "select", and its argument is a unique function,
456;;; add the rule to the lists for both "select" and that function.
457;;; (Currently rules like this go on the "nil" list.)
458;;; Same for "func-opt" functions. (Though not urgent for these.)
459;;;
460;;; * Shouldn't evaluate a "let" condition until the end, or until it
461;;; would enable another condition to be evaluated.
462;;;
463
464;;; Some additional features to add / things to think about:
465;;;
466;;; * Figure out what happens to "a +/- b" and "a +/- opt(b)".
467;;;
468;;; * Same for interval forms.
469;;;
470;;; * Have a name(v,pat) pattern which matches pat, and gives the
471;;; whole match the name v. Beware of circular structures!
472;;;
473
474(defun math-compile-patterns (pats)
475 (if (and (eq (car-safe pats) 'var)
476 (calc-var-value (nth 2 pats)))
477 (let ((prop (get (nth 2 pats) 'math-pattern-cache)))
478 (or prop
479 (put (nth 2 pats) 'math-pattern-cache (setq prop (list nil))))
480 (or (eq (car prop) (symbol-value (nth 2 pats)))
481 (progn
482 (setcdr prop (math-compile-patterns
483 (symbol-value (nth 2 pats))))
484 (setcar prop (symbol-value (nth 2 pats)))))
485 (cdr prop))
486 (let ((math-rewrite-whole t))
487 (cdr (math-compile-rewrites (cons
488 'vec
489 (mapcar (function (lambda (x)
490 (list 'vec x t)))
491 (if (eq (car-safe pats) 'vec)
492 (cdr pats)
bf77c646 493 (list pats)))))))))
136211a9 494
3132f345
CW
495(defvar math-rewrite-whole nil)
496(defvar math-make-import-list nil)
40ead937
JB
497
498;; The variable math-import-list is local to part of math-compile-rewrites,
499;; but is also used in a different part, and so the local version could
500;; be affected by the non-local version when math-compile-rewrites calls itself.
501(defvar math-import-list nil)
502
503;; The variables math-regs, math-num-regs, math-prog-last, math-bound-vars,
504;; math-conds, math-copy-neg, math-rhs, math-pattern, math-remembering and
505;; math-aliased-vars are local to math-compile-rewrites,
506;; but are used by many functions math-rwcomp-*, which are called by
507;; math-compile-rewrites.
508(defvar math-regs)
509(defvar math-num-regs)
510(defvar math-prog-last)
511(defvar math-bound-vars)
512(defvar math-conds)
513(defvar math-copy-neg)
514(defvar math-rhs)
515(defvar math-pattern)
516(defvar math-remembering)
517(defvar math-aliased-vars)
518
136211a9
EZ
519(defun math-compile-rewrites (rules &optional name)
520 (if (eq (car-safe rules) 'var)
521 (let ((prop (get (nth 2 rules) 'math-rewrite-cache))
522 (math-import-list nil)
523 (math-make-import-list t)
524 p)
525 (or (calc-var-value (nth 2 rules))
526 (error "Rules variable %s has no stored value" (nth 1 rules)))
527 (or prop
528 (put (nth 2 rules) 'math-rewrite-cache
529 (setq prop (list (list (cons (nth 2 rules) nil))))))
530 (setq p (car prop))
531 (while (and p (eq (symbol-value (car (car p))) (cdr (car p))))
532 (setq p (cdr p)))
533 (or (null p)
534 (progn
535 (message "Compiling rule set %s..." (nth 1 rules))
536 (setcdr prop (math-compile-rewrites
537 (symbol-value (nth 2 rules))
538 (nth 2 rules)))
539 (message "Compiling rule set %s...done" (nth 1 rules))
540 (setcar prop (cons (cons (nth 2 rules)
541 (symbol-value (nth 2 rules)))
542 math-import-list))))
543 (cdr prop))
544 (if (or (not (eq (car-safe rules) 'vec))
545 (and (memq (length rules) '(3 4))
546 (let ((p rules))
547 (while (and (setq p (cdr p))
548 (memq (car-safe (car p))
549 '(vec
550 calcFunc-assign
551 calcFunc-condition
552 calcFunc-import
553 calcFunc-phase
554 calcFunc-schedule
555 calcFunc-iterations))))
556 p)))
557 (setq rules (list rules))
558 (setq rules (cdr rules)))
559 (if (assq 'calcFunc-import rules)
560 (let ((pp (setq rules (copy-sequence rules)))
561 p part)
562 (while (setq p (car (cdr pp)))
563 (if (eq (car-safe p) 'calcFunc-import)
564 (progn
565 (setcdr pp (cdr (cdr pp)))
566 (or (and (eq (car-safe (nth 1 p)) 'var)
567 (setq part (calc-var-value (nth 2 (nth 1 p))))
568 (memq (car-safe part) '(vec
569 calcFunc-assign
570 calcFunc-condition)))
571 (error "Argument of import() must be a rules variable"))
572 (if math-make-import-list
573 (setq math-import-list
574 (cons (cons (nth 2 (nth 1 p))
575 (symbol-value (nth 2 (nth 1 p))))
576 math-import-list)))
577 (while (setq p (cdr (cdr p)))
578 (or (cdr p)
579 (error "import() must have odd number of arguments"))
580 (setq part (math-rwcomp-substitute part
581 (car p) (nth 1 p))))
582 (if (eq (car-safe part) 'vec)
583 (setq part (cdr part))
584 (setq part (list part)))
585 (setcdr pp (append part (cdr pp))))
586 (setq pp (cdr pp))))))
587 (let ((rule-set nil)
588 (all-heads nil)
589 (nil-rules nil)
590 (rule-count 0)
591 (math-schedule nil)
592 (math-iterations nil)
593 (math-phases nil)
594 (math-all-phases nil)
595 (math-remembering nil)
596 math-pattern math-rhs math-conds)
597 (while rules
598 (cond
599 ((and (eq (car-safe (car rules)) 'calcFunc-iterations)
600 (= (length (car rules)) 2))
601 (or (integerp (nth 1 (car rules)))
602 (equal (nth 1 (car rules)) '(var inf var-inf))
603 (equal (nth 1 (car rules)) '(neg (var inf var-inf)))
604 (error "Invalid argument for iterations(n)"))
605 (or math-iterations
606 (setq math-iterations (nth 1 (car rules)))))
607 ((eq (car-safe (car rules)) 'calcFunc-schedule)
608 (or math-schedule
609 (setq math-schedule (math-parse-schedule (cdr (car rules))))))
610 ((eq (car-safe (car rules)) 'calcFunc-phase)
611 (setq math-phases (cdr (car rules)))
612 (if (equal math-phases '((var all var-all)))
613 (setq math-phases nil))
614 (let ((p math-phases))
615 (while p
616 (or (integerp (car p))
617 (error "Phase numbers must be small integers"))
618 (or (memq (car p) math-all-phases)
619 (setq math-all-phases (cons (car p) math-all-phases)))
620 (setq p (cdr p)))))
621 ((or (and (eq (car-safe (car rules)) 'vec)
622 (cdr (cdr (car rules)))
623 (not (nthcdr 4 (car rules)))
624 (setq math-conds (nth 3 (car rules))
625 math-rhs (nth 2 (car rules))
626 math-pattern (nth 1 (car rules))))
627 (progn
628 (setq math-conds nil
629 math-pattern (car rules))
630 (while (and (eq (car-safe math-pattern) 'calcFunc-condition)
631 (= (length math-pattern) 3))
632 (let ((cond (nth 2 math-pattern)))
633 (setq math-conds (if math-conds
634 (list 'calcFunc-land math-conds cond)
635 cond)
636 math-pattern (nth 1 math-pattern))))
637 (and (eq (car-safe math-pattern) 'calcFunc-assign)
638 (= (length math-pattern) 3)
639 (setq math-rhs (nth 2 math-pattern)
640 math-pattern (nth 1 math-pattern)))))
641 (let* ((math-prog (list nil))
642 (math-prog-last math-prog)
643 (math-num-regs 1)
644 (math-regs (list (list nil 0 nil nil)))
645 (math-bound-vars nil)
646 (math-aliased-vars nil)
647 (math-copy-neg nil))
648 (setq math-conds (and math-conds (math-flatten-lands math-conds)))
649 (math-rwcomp-pattern math-pattern 0)
650 (while math-conds
651 (let ((expr (car math-conds)))
652 (setq math-conds (cdr math-conds))
653 (math-rwcomp-cond-instr expr)))
654 (math-rwcomp-instr 'done
655 (if (eq math-rhs t)
656 (cons 'vec
657 (delq
658 nil
659 (nreverse
660 (mapcar
661 (function
662 (lambda (v)
663 (and (car v)
664 (list
665 'calcFunc-assign
666 (math-build-var-name
667 (car v))
668 (math-rwcomp-register-expr
669 (nth 1 v))))))
670 math-regs))))
671 (math-rwcomp-match-vars math-rhs))
672 math-remembering)
673 (setq math-prog (cdr math-prog))
674 (let* ((heads (math-rewrite-heads math-pattern))
675 (rule (list (vconcat
676 (nreverse
677 (mapcar (function (lambda (x) (nth 3 x)))
678 math-regs)))
679 math-prog
680 heads
681 math-phases))
682 (head (and (not (Math-primp math-pattern))
683 (not (and (eq (car (car math-prog)) 'try)
684 (nth 5 (car math-prog))))
685 (not (memq (car (car math-prog)) '(func-opt
686 apply
687 select
688 alt)))
689 (if (memq (car (car math-prog)) '(func
690 func-def))
691 (nth 2 (car math-prog))
692 (if (eq (car math-pattern) 'calcFunc-quote)
693 (car-safe (nth 1 math-pattern))
694 (car math-pattern))))))
695 (let (found)
696 (while heads
697 (if (setq found (assq (car heads) all-heads))
698 (setcdr found (1+ (cdr found)))
699 (setq all-heads (cons (cons (car heads) 1) all-heads)))
700 (setq heads (cdr heads))))
701 (if (eq head '-) (setq head '+))
702 (if (memq head '(calcFunc-cons calcFunc-rcons)) (setq head 'vec))
703 (if head
704 (progn
705 (nconc (or (assq head rule-set)
706 (car (setq rule-set (cons (cons head
707 (copy-sequence
708 nil-rules))
709 rule-set))))
710 (list rule))
711 (if (eq head '*)
712 (nconc (or (assq '/ rule-set)
713 (car (setq rule-set (cons (cons
714 '/
715 (copy-sequence
716 nil-rules))
717 rule-set))))
718 (list rule))))
719 (setq nil-rules (nconc nil-rules (list rule)))
720 (let ((ptr rule-set))
721 (while ptr
722 (nconc (car ptr) (list rule))
723 (setq ptr (cdr ptr))))))))
724 (t
725 (error "Rewrite rule set must be a vector of A := B rules")))
726 (setq rules (cdr rules)))
727 (if nil-rules
728 (setq rule-set (cons (cons nil nil-rules) rule-set)))
729 (setq all-heads (mapcar 'car
730 (sort all-heads (function
731 (lambda (x y)
732 (< (cdr x) (cdr y)))))))
733 (let ((set rule-set)
734 rule heads ptr)
735 (while set
736 (setq rule (cdr (car set)))
737 (while rule
738 (if (consp (setq heads (nth 2 (car rule))))
739 (progn
740 (setq heads (delq (car (car set)) heads)
741 ptr all-heads)
742 (while (and ptr (not (memq (car ptr) heads)))
743 (setq ptr (cdr ptr)))
744 (setcar (nthcdr 2 (car rule)) (car ptr))))
745 (setq rule (cdr rule)))
746 (setq set (cdr set))))
747 (let ((plus (assq '+ rule-set)))
748 (if plus
749 (setq rule-set (cons (cons '- (cdr plus)) rule-set))))
750 (cons (list 'schedule math-iterations name
751 (or math-schedule
752 (sort math-all-phases '<)
753 (list 1)))
bf77c646 754 rule-set))))
136211a9
EZ
755
756(defun math-flatten-lands (expr)
757 (if (eq (car-safe expr) 'calcFunc-land)
758 (append (math-flatten-lands (nth 1 expr))
759 (math-flatten-lands (nth 2 expr)))
bf77c646 760 (list expr)))
136211a9 761
40ead937
JB
762;; The variables math-rewrite-heads-heads (i.e.; heads for math-rewrite-heads)
763;; math-rewrite-heads-blanks and math-rewrite-heads-skips are local to
764;; math-rewrite-heads, but used by math-rewrite-heads-rec, which is called by
765;; math-rewrite-heads.
766(defvar math-rewrite-heads-heads)
767(defvar math-rewrite-heads-skips)
768(defvar math-rewrite-heads-blanks)
769
136211a9 770(defun math-rewrite-heads (expr &optional more all)
40ead937
JB
771 (let ((math-rewrite-heads-heads more)
772 (math-rewrite-heads-skips (and (not all)
136211a9
EZ
773 '(calcFunc-apply calcFunc-condition calcFunc-opt
774 calcFunc-por calcFunc-pnot)))
40ead937 775 (math-rewrite-heads-blanks (and (not all)
136211a9
EZ
776 '(calcFunc-quote calcFunc-plain calcFunc-select
777 calcFunc-cons calcFunc-rcons
778 calcFunc-pand))))
779 (or (Math-primp expr)
780 (math-rewrite-heads-rec expr))
40ead937 781 math-rewrite-heads-heads))
136211a9
EZ
782
783(defun math-rewrite-heads-rec (expr)
40ead937 784 (or (memq (car expr) math-rewrite-heads-skips)
136211a9 785 (progn
40ead937
JB
786 (or (memq (car expr) math-rewrite-heads-heads)
787 (memq (car expr) math-rewrite-heads-blanks)
136211a9 788 (memq 'algebraic (get (car expr) 'math-rewrite-props))
40ead937 789 (setq math-rewrite-heads-heads (cons (car expr) math-rewrite-heads-heads)))
136211a9
EZ
790 (while (setq expr (cdr expr))
791 (or (Math-primp (car expr))
bf77c646 792 (math-rewrite-heads-rec (car expr)))))))
136211a9
EZ
793
794(defun math-parse-schedule (sched)
795 (mapcar (function
796 (lambda (s)
797 (if (integerp s)
798 s
799 (if (math-vectorp s)
800 (math-parse-schedule (cdr s))
801 (if (eq (car-safe s) 'var)
802 (math-var-to-calcFunc s)
803 (error "Improper component in rewrite schedule"))))))
bf77c646 804 sched))
136211a9
EZ
805
806(defun math-rwcomp-match-vars (expr)
807 (if (Math-primp expr)
808 (if (eq (car-safe expr) 'var)
809 (let ((entry (assq (nth 2 expr) math-regs)))
810 (if entry
811 (math-rwcomp-register-expr (nth 1 entry))
812 expr))
813 expr)
814 (if (and (eq (car expr) 'calcFunc-quote)
815 (= (length expr) 2))
816 (math-rwcomp-match-vars (nth 1 expr))
817 (if (and (eq (car expr) 'calcFunc-plain)
818 (= (length expr) 2)
819 (not (Math-primp (nth 1 expr))))
820 (list (car expr)
821 (cons (car (nth 1 expr))
822 (mapcar 'math-rwcomp-match-vars (cdr (nth 1 expr)))))
823 (cons (car expr)
bf77c646 824 (mapcar 'math-rwcomp-match-vars (cdr expr)))))))
136211a9
EZ
825
826(defun math-rwcomp-register-expr (num)
827 (let ((entry (nth (1- (- math-num-regs num)) math-regs)))
828 (if (nth 2 entry)
829 (list 'neg (list 'calcFunc-register (nth 1 entry)))
bf77c646 830 (list 'calcFunc-register (nth 1 entry)))))
136211a9 831
40ead937
JB
832;; The variables math-rwcomp-subst-old, math-rwcomp-subst-new,
833;; math-rwcomp-subst-old-func and math-rwcomp-subst-new-func
834;; are local to math-rwcomp-substitute, but are used by
835;; math-rwcomp-subst-rec, which is called by math-rwcomp-substitute.
836(defvar math-rwcomp-subst-new)
837(defvar math-rwcomp-subst-old)
838(defvar math-rwcomp-subst-new-func)
839(defvar math-rwcomp-subst-old-func)
840
841(defun math-rwcomp-substitute (expr math-rwcomp-subst-old math-rwcomp-subst-new)
842 (if (and (eq (car-safe math-rwcomp-subst-old) 'var)
843 (memq (car-safe math-rwcomp-subst-new) '(var calcFunc-lambda)))
844 (let ((math-rwcomp-subst-old-func (math-var-to-calcFunc math-rwcomp-subst-old))
845 (math-rwcomp-subst-new-func (math-var-to-calcFunc math-rwcomp-subst-new)))
136211a9 846 (math-rwcomp-subst-rec expr))
40ead937 847 (let ((math-rwcomp-subst-old-func nil))
bf77c646 848 (math-rwcomp-subst-rec expr))))
136211a9
EZ
849
850(defun math-rwcomp-subst-rec (expr)
40ead937 851 (cond ((equal expr math-rwcomp-subst-old) math-rwcomp-subst-new)
136211a9 852 ((Math-primp expr) expr)
40ead937
JB
853 (t (if (eq (car expr) math-rwcomp-subst-old-func)
854 (math-build-call math-rwcomp-subst-new-func
855 (mapcar 'math-rwcomp-subst-rec
856 (cdr expr)))
136211a9 857 (cons (car expr)
bf77c646 858 (mapcar 'math-rwcomp-subst-rec (cdr expr)))))))
136211a9 859
3132f345 860(defvar math-rwcomp-tracing nil)
136211a9
EZ
861
862(defun math-rwcomp-trace (instr)
3132f345
CW
863 (when math-rwcomp-tracing
864 (terpri) (princ instr))
bf77c646 865 instr)
136211a9
EZ
866
867(defun math-rwcomp-instr (&rest instr)
868 (setcdr math-prog-last
bf77c646 869 (setq math-prog-last (list (math-rwcomp-trace instr)))))
136211a9
EZ
870
871(defun math-rwcomp-multi-instr (tail &rest instr)
872 (setcdr math-prog-last
bf77c646 873 (setq math-prog-last (list (math-rwcomp-trace (append instr tail))))))
136211a9
EZ
874
875(defun math-rwcomp-bind-var (reg var)
876 (setcar (math-rwcomp-reg-entry reg) (nth 2 var))
877 (setq math-bound-vars (cons (nth 2 var) math-bound-vars))
bf77c646 878 (math-rwcomp-do-conditions))
136211a9
EZ
879
880(defun math-rwcomp-unbind-vars (mark)
881 (while (not (eq math-bound-vars mark))
882 (setcar (assq (car math-bound-vars) math-regs) nil)
bf77c646 883 (setq math-bound-vars (cdr math-bound-vars))))
136211a9
EZ
884
885(defun math-rwcomp-do-conditions ()
886 (let ((cond math-conds))
887 (while cond
888 (if (math-rwcomp-all-regs-done (car cond))
889 (let ((expr (car cond)))
890 (setq math-conds (delq (car cond) math-conds))
891 (setcar cond 1)
892 (math-rwcomp-cond-instr expr)))
bf77c646 893 (setq cond (cdr cond)))))
136211a9
EZ
894
895(defun math-rwcomp-cond-instr (expr)
896 (let (op arg)
897 (cond ((and (eq (car-safe expr) 'calcFunc-matches)
898 (= (length expr) 3)
899 (eq (car-safe (setq arg (math-rwcomp-match-vars (nth 1 expr))))
900 'calcFunc-register))
901 (math-rwcomp-pattern (nth 2 expr) (nth 1 arg)))
902 ((math-numberp (setq expr (math-rwcomp-match-vars expr)))
903 (if (Math-zerop expr)
904 (math-rwcomp-instr 'backtrack)))
905 ((and (eq (car expr) 'calcFunc-let)
906 (= (length expr) 3))
907 (let ((reg (math-rwcomp-reg)))
908 (math-rwcomp-instr 'let reg (nth 2 expr))
909 (math-rwcomp-pattern (nth 1 expr) reg)))
910 ((and (eq (car expr) 'calcFunc-let)
911 (= (length expr) 2)
912 (eq (car-safe (nth 1 expr)) 'calcFunc-assign)
913 (= (length (nth 1 expr)) 3))
914 (let ((reg (math-rwcomp-reg)))
915 (math-rwcomp-instr 'let reg (nth 2 (nth 1 expr)))
916 (math-rwcomp-pattern (nth 1 (nth 1 expr)) reg)))
917 ((and (setq op (cdr (assq (car-safe expr)
918 '( (calcFunc-integer . integer)
919 (calcFunc-real . real)
920 (calcFunc-constant . constant)
921 (calcFunc-negative . negative) ))))
922 (= (length expr) 2)
923 (or (and (eq (car-safe (nth 1 expr)) 'neg)
924 (memq op '(integer real constant))
925 (setq arg (nth 1 (nth 1 expr))))
926 (setq arg (nth 1 expr)))
927 (eq (car-safe (setq arg (nth 1 expr))) 'calcFunc-register))
928 (math-rwcomp-instr op (nth 1 arg)))
929 ((and (assq (car-safe expr) calc-tweak-eqn-table)
930 (= (length expr) 3)
931 (eq (car-safe (nth 1 expr)) 'calcFunc-register))
932 (if (math-constp (nth 2 expr))
933 (let ((reg (math-rwcomp-reg)))
934 (setcar (nthcdr 3 (car math-regs)) (nth 2 expr))
935 (math-rwcomp-instr 'rel (nth 1 (nth 1 expr))
936 (car expr) reg))
937 (if (eq (car (nth 2 expr)) 'calcFunc-register)
938 (math-rwcomp-instr 'rel (nth 1 (nth 1 expr))
939 (car expr) (nth 1 (nth 2 expr)))
940 (math-rwcomp-instr 'cond expr))))
941 ((and (eq (car-safe expr) 'calcFunc-eq)
942 (= (length expr) 3)
943 (eq (car-safe (nth 1 expr)) '%)
944 (eq (car-safe (nth 1 (nth 1 expr))) 'calcFunc-register)
945 (math-constp (nth 2 (nth 1 expr)))
946 (math-constp (nth 2 expr)))
947 (math-rwcomp-instr 'mod (nth 1 (nth 1 (nth 1 expr)))
948 (nth 2 (nth 1 expr)) (nth 2 expr)))
949 ((equal expr '(var remember var-remember))
950 (setq math-remembering 1))
951 ((and (eq (car-safe expr) 'calcFunc-remember)
952 (= (length expr) 2))
953 (setq math-remembering (if math-remembering
954 (list 'calcFunc-lor
955 math-remembering (nth 1 expr))
956 (nth 1 expr))))
bf77c646 957 (t (math-rwcomp-instr 'cond expr)))))
136211a9
EZ
958
959(defun math-rwcomp-same-instr (reg1 reg2 neg)
960 (math-rwcomp-instr (if (eq (eq (nth 2 (math-rwcomp-reg-entry reg1))
961 (nth 2 (math-rwcomp-reg-entry reg2)))
962 neg)
963 'same-neg
964 'same)
bf77c646 965 reg1 reg2))
136211a9
EZ
966
967(defun math-rwcomp-copy-instr (reg1 reg2 neg)
968 (if (eq (eq (nth 2 (math-rwcomp-reg-entry reg1))
969 (nth 2 (math-rwcomp-reg-entry reg2)))
970 neg)
971 (math-rwcomp-instr 'copy-neg reg1 reg2)
972 (or (eq reg1 reg2)
bf77c646 973 (math-rwcomp-instr 'copy reg1 reg2))))
136211a9
EZ
974
975(defun math-rwcomp-reg ()
976 (prog1
977 math-num-regs
978 (setq math-regs (cons (list nil math-num-regs nil 0) math-regs)
bf77c646 979 math-num-regs (1+ math-num-regs))))
136211a9
EZ
980
981(defun math-rwcomp-reg-entry (num)
bf77c646 982 (nth (1- (- math-num-regs num)) math-regs))
136211a9
EZ
983
984
985(defun math-rwcomp-pattern (expr part &optional not-direct)
986 (cond ((or (math-rwcomp-no-vars expr)
987 (and (eq (car expr) 'calcFunc-quote)
988 (= (length expr) 2)
989 (setq expr (nth 1 expr))))
990 (if (eq (car-safe expr) 'calcFunc-register)
991 (math-rwcomp-same-instr part (nth 1 expr) nil)
992 (let ((reg (math-rwcomp-reg)))
993 (setcar (nthcdr 3 (car math-regs)) expr)
994 (math-rwcomp-same-instr part reg nil))))
995 ((eq (car expr) 'var)
996 (let ((entry (assq (nth 2 expr) math-regs)))
997 (if entry
998 (math-rwcomp-same-instr part (nth 1 entry) nil)
999 (if not-direct
1000 (let ((reg (math-rwcomp-reg)))
1001 (math-rwcomp-pattern expr reg)
1002 (math-rwcomp-copy-instr part reg nil))
1003 (if (setq entry (assq (nth 2 expr) math-aliased-vars))
1004 (progn
1005 (setcar (math-rwcomp-reg-entry (nth 1 entry))
1006 (nth 2 expr))
1007 (setcar entry nil)
1008 (math-rwcomp-copy-instr part (nth 1 entry) nil))
1009 (math-rwcomp-bind-var part expr))))))
1010 ((and (eq (car expr) 'calcFunc-select)
1011 (= (length expr) 2))
1012 (let ((reg (math-rwcomp-reg)))
1013 (math-rwcomp-instr 'select part reg)
1014 (math-rwcomp-pattern (nth 1 expr) reg)))
1015 ((and (eq (car expr) 'calcFunc-opt)
1016 (memq (length expr) '(2 3)))
1017 (error "opt( ) occurs in context where it is not allowed"))
1018 ((eq (car expr) 'neg)
1019 (if (eq (car (nth 1 expr)) 'var)
1020 (let ((entry (assq (nth 2 (nth 1 expr)) math-regs)))
1021 (if entry
1022 (math-rwcomp-same-instr part (nth 1 entry) t)
1023 (if math-copy-neg
1024 (let ((reg (math-rwcomp-best-reg (nth 1 expr))))
1025 (math-rwcomp-copy-instr part reg t)
1026 (math-rwcomp-pattern (nth 1 expr) reg))
1027 (setcar (cdr (cdr (math-rwcomp-reg-entry part))) t)
1028 (math-rwcomp-pattern (nth 1 expr) part))))
1029 (if (math-rwcomp-is-algebraic (nth 1 expr))
1030 (math-rwcomp-cond-instr (list 'calcFunc-eq
1031 (math-rwcomp-register-expr part)
1032 expr))
1033 (let ((reg (math-rwcomp-reg)))
1034 (math-rwcomp-instr 'func part 'neg reg)
1035 (math-rwcomp-pattern (nth 1 expr) reg)))))
1036 ((and (eq (car expr) 'calcFunc-apply)
1037 (= (length expr) 3))
1038 (let ((reg1 (math-rwcomp-reg))
1039 (reg2 (math-rwcomp-reg)))
1040 (math-rwcomp-instr 'apply part reg1 reg2)
1041 (math-rwcomp-pattern (nth 1 expr) reg1)
1042 (math-rwcomp-pattern (nth 2 expr) reg2)))
1043 ((and (eq (car expr) 'calcFunc-cons)
1044 (= (length expr) 3))
1045 (let ((reg1 (math-rwcomp-reg))
1046 (reg2 (math-rwcomp-reg)))
1047 (math-rwcomp-instr 'cons part reg1 reg2)
1048 (math-rwcomp-pattern (nth 1 expr) reg1)
1049 (math-rwcomp-pattern (nth 2 expr) reg2)))
1050 ((and (eq (car expr) 'calcFunc-rcons)
1051 (= (length expr) 3))
1052 (let ((reg1 (math-rwcomp-reg))
1053 (reg2 (math-rwcomp-reg)))
1054 (math-rwcomp-instr 'rcons part reg1 reg2)
1055 (math-rwcomp-pattern (nth 1 expr) reg1)
1056 (math-rwcomp-pattern (nth 2 expr) reg2)))
1057 ((and (eq (car expr) 'calcFunc-condition)
1058 (>= (length expr) 3))
1059 (math-rwcomp-pattern (nth 1 expr) part)
1060 (setq expr (cdr expr))
1061 (while (setq expr (cdr expr))
1062 (let ((cond (math-flatten-lands (car expr))))
1063 (while cond
1064 (if (math-rwcomp-all-regs-done (car cond))
1065 (math-rwcomp-cond-instr (car cond))
1066 (setq math-conds (cons (car cond) math-conds)))
1067 (setq cond (cdr cond))))))
1068 ((and (eq (car expr) 'calcFunc-pand)
1069 (= (length expr) 3))
1070 (math-rwcomp-pattern (nth 1 expr) part)
1071 (math-rwcomp-pattern (nth 2 expr) part))
1072 ((and (eq (car expr) 'calcFunc-por)
1073 (= (length expr) 3))
1074 (math-rwcomp-instr 'alt nil nil [nil nil 4])
1075 (let ((math-conds nil)
1076 (head math-prog-last)
1077 (mark math-bound-vars)
1078 (math-copy-neg t))
1079 (math-rwcomp-pattern (nth 1 expr) part t)
1080 (let ((amark math-aliased-vars)
1081 (math-aliased-vars math-aliased-vars)
1082 (tail math-prog-last)
1083 (p math-bound-vars)
1084 entry)
1085 (while (not (eq p mark))
1086 (setq entry (assq (car p) math-regs)
1087 math-aliased-vars (cons (list (car p) (nth 1 entry) nil)
1088 math-aliased-vars)
1089 p (cdr p))
1090 (setcar (math-rwcomp-reg-entry (nth 1 entry)) nil))
1091 (setcar (cdr (car head)) (cdr head))
1092 (setcdr head nil)
1093 (setq math-prog-last head)
1094 (math-rwcomp-pattern (nth 2 expr) part)
1095 (math-rwcomp-instr 'same 0 0)
1096 (setcdr tail math-prog-last)
1097 (setq p math-aliased-vars)
1098 (while (not (eq p amark))
1099 (if (car (car p))
1100 (setcar (math-rwcomp-reg-entry (nth 1 (car p)))
1101 (car (car p))))
1102 (setq p (cdr p)))))
1103 (math-rwcomp-do-conditions))
1104 ((and (eq (car expr) 'calcFunc-pnot)
1105 (= (length expr) 2))
1106 (math-rwcomp-instr 'alt nil nil [nil nil 4])
1107 (let ((head math-prog-last)
1108 (mark math-bound-vars))
1109 (math-rwcomp-pattern (nth 1 expr) part)
1110 (math-rwcomp-unbind-vars mark)
1111 (math-rwcomp-instr 'end-alt head)
1112 (math-rwcomp-instr 'backtrack)
1113 (setcar (cdr (car head)) (cdr head))
1114 (setcdr head nil)
1115 (setq math-prog-last head)))
1116 (t (let ((props (get (car expr) 'math-rewrite-props)))
1117 (if (and (eq (car expr) 'calcFunc-plain)
1118 (= (length expr) 2)
1119 (not (math-primp (nth 1 expr))))
1120 (setq expr (nth 1 expr))) ; but "props" is still nil
1121 (if (and (memq 'algebraic props)
1122 (math-rwcomp-is-algebraic expr))
1123 (math-rwcomp-cond-instr (list 'calcFunc-eq
1124 (math-rwcomp-register-expr part)
1125 expr))
1126 (if (and (memq 'commut props)
1127 (= (length expr) 3))
1128 (let ((arg1 (nth 1 expr))
1129 (arg2 (nth 2 expr))
1130 try1 def code head (flip nil))
1131 (if (eq (car expr) '-)
1132 (setq arg2 (math-rwcomp-neg arg2)))
1133 (setq arg1 (cons arg1 (math-rwcomp-best-reg arg1))
1134 arg2 (cons arg2 (math-rwcomp-best-reg arg2)))
1135 (or (math-rwcomp-order arg1 arg2)
1136 (setq def arg1 arg1 arg2 arg2 def flip t))
1137 (if (math-rwcomp-optional-arg (car expr) arg1)
1138 (error "Too many opt( ) arguments in this context"))
1139 (setq def (math-rwcomp-optional-arg (car expr) arg2)
1140 head (if (memq (car expr) '(+ -))
1141 '(+ -)
1142 (if (eq (car expr) '*)
1143 '(* /)
1144 (list (car expr))))
1145 code (if (math-rwcomp-is-constrained
1146 (car arg1) head)
1147 (if (math-rwcomp-is-constrained
1148 (car arg2) head)
1149 0 1)
1150 2))
1151 (math-rwcomp-multi-instr (and def (list def))
1152 'try part head
1153 (vector nil nil nil code flip)
1154 (cdr arg1))
1155 (setq try1 (car math-prog-last))
1156 (math-rwcomp-pattern (car arg1) (cdr arg1))
1157 (math-rwcomp-instr 'try2 try1 (cdr arg2))
1158 (if (and (= part 0) (not def) (not math-rewrite-whole)
1159 (not (eq math-rhs t))
1160 (setq def (get (car expr)
1161 'math-rewrite-default)))
1162 (let ((reg1 (math-rwcomp-reg))
1163 (reg2 (math-rwcomp-reg)))
1164 (if (= (aref (nth 3 try1) 3) 0)
1165 (aset (nth 3 try1) 3 1))
1166 (math-rwcomp-instr 'try (cdr arg2)
1167 (if (equal head '(* /))
1168 '(*) head)
1169 (vector nil nil nil
1170 (if (= code 0)
1171 1 2)
1172 nil)
1173 reg1 def)
1174 (setq try1 (car math-prog-last))
1175 (math-rwcomp-pattern (car arg2) reg1)
1176 (math-rwcomp-instr 'try2 try1 reg2)
1177 (setq math-rhs (list (if (eq (car expr) '-)
1178 '+ (car expr))
1179 math-rhs
1180 (list 'calcFunc-register
1181 reg2))))
1182 (math-rwcomp-pattern (car arg2) (cdr arg2))))
1183 (let* ((args (mapcar (function
1184 (lambda (x)
1185 (cons x (math-rwcomp-best-reg x))))
1186 (cdr expr)))
1187 (args2 (copy-sequence args))
1188 (argp (reverse args2))
1189 (defs nil)
1190 (num 1))
1191 (while argp
1192 (let ((def (math-rwcomp-optional-arg (car expr)
1193 (car argp))))
1194 (if def
1195 (progn
1196 (setq args2 (delq (car argp) args2)
1197 defs (cons (cons def (cdr (car argp)))
1198 defs))
1199 (math-rwcomp-multi-instr
1200 (mapcar 'cdr args2)
1201 (if (or (and (memq 'unary1 props)
1202 (= (length args2) 1)
1203 (eq (car args2) (car args)))
1204 (and (memq 'unary2 props)
1205 (= (length args) 2)
1206 (eq (car args2) (nth 1 args))))
1207 'func-opt
1208 'func-def)
1209 part (car expr)
1210 defs))))
1211 (setq argp (cdr argp)))
1212 (math-rwcomp-multi-instr (mapcar 'cdr args)
1213 'func part (car expr))
1214 (setq args (sort args 'math-rwcomp-order))
1215 (while args
1216 (math-rwcomp-pattern (car (car args)) (cdr (car args)))
1217 (setq num (1+ num)
bf77c646 1218 args (cdr args))))))))))
136211a9
EZ
1219
1220(defun math-rwcomp-best-reg (x)
1221 (or (and (eq (car-safe x) 'var)
1222 (let ((entry (assq (nth 2 x) math-aliased-vars)))
1223 (and entry
1224 (not (nth 2 entry))
1225 (not (nth 2 (math-rwcomp-reg-entry (nth 1 entry))))
1226 (progn
1227 (setcar (cdr (cdr entry)) t)
1228 (nth 1 entry)))))
bf77c646 1229 (math-rwcomp-reg)))
136211a9
EZ
1230
1231(defun math-rwcomp-all-regs-done (expr)
1232 (if (Math-primp expr)
1233 (or (not (eq (car-safe expr) 'var))
1234 (assq (nth 2 expr) math-regs)
1235 (eq (nth 2 expr) 'var-remember)
1236 (math-const-var expr))
1237 (if (and (eq (car expr) 'calcFunc-let)
1238 (= (length expr) 3))
1239 (math-rwcomp-all-regs-done (nth 2 expr))
1240 (if (and (eq (car expr) 'calcFunc-let)
1241 (= (length expr) 2)
1242 (eq (car-safe (nth 1 expr)) 'calcFunc-assign)
1243 (= (length (nth 1 expr)) 3))
1244 (math-rwcomp-all-regs-done (nth 2 (nth 1 expr)))
1245 (while (and (setq expr (cdr expr))
1246 (math-rwcomp-all-regs-done (car expr))))
bf77c646 1247 (null expr)))))
136211a9
EZ
1248
1249(defun math-rwcomp-no-vars (expr)
1250 (if (Math-primp expr)
1251 (or (not (eq (car-safe expr) 'var))
1252 (math-const-var expr))
1253 (and (not (memq (car expr) '(calcFunc-condition
1254 calcFunc-select calcFunc-quote
1255 calcFunc-plain calcFunc-opt
1256 calcFunc-por calcFunc-pand
1257 calcFunc-pnot calcFunc-apply
1258 calcFunc-cons calcFunc-rcons)))
1259 (progn
1260 (while (and (setq expr (cdr expr))
1261 (math-rwcomp-no-vars (car expr))))
bf77c646 1262 (null expr)))))
136211a9
EZ
1263
1264(defun math-rwcomp-is-algebraic (expr)
1265 (if (Math-primp expr)
1266 (or (not (eq (car-safe expr) 'var))
1267 (math-const-var expr)
1268 (assq (nth 2 expr) math-regs))
1269 (and (memq 'algebraic (get (car expr) 'math-rewrite-props))
1270 (progn
1271 (while (and (setq expr (cdr expr))
1272 (math-rwcomp-is-algebraic (car expr))))
bf77c646 1273 (null expr)))))
136211a9
EZ
1274
1275(defun math-rwcomp-is-constrained (expr not-these)
1276 (if (Math-primp expr)
1277 (not (eq (car-safe expr) 'var))
1278 (if (eq (car expr) 'calcFunc-plain)
1279 (math-rwcomp-is-constrained (nth 1 expr) not-these)
1280 (not (or (memq (car expr) '(neg calcFunc-select))
1281 (memq (car expr) not-these)
1282 (and (memq 'commut (get (car expr) 'math-rewrite-props))
1283 (or (eq (car-safe (nth 1 expr)) 'calcFunc-opt)
bf77c646 1284 (eq (car-safe (nth 2 expr)) 'calcFunc-opt))))))))
136211a9
EZ
1285
1286(defun math-rwcomp-optional-arg (head argp)
1287 (let ((arg (car argp)))
1288 (if (eq (car-safe arg) 'calcFunc-opt)
1289 (and (memq (length arg) '(2 3))
1290 (progn
1291 (or (eq (car-safe (nth 1 arg)) 'var)
1292 (error "First argument of opt( ) must be a variable"))
1293 (setcar argp (nth 1 arg))
1294 (if (= (length arg) 2)
1295 (or (get head 'math-rewrite-default)
1296 (error "opt( ) must include a default in this context"))
1297 (nth 2 arg))))
1298 (and (eq (car-safe arg) 'neg)
1299 (let* ((part (list (nth 1 arg)))
1300 (partp (math-rwcomp-optional-arg head part)))
1301 (and partp
1302 (setcar argp (math-rwcomp-neg (car part)))
bf77c646 1303 (math-neg partp)))))))
136211a9
EZ
1304
1305(defun math-rwcomp-neg (expr)
1306 (if (memq (car-safe expr) '(* /))
1307 (if (eq (car-safe (nth 1 expr)) 'var)
1308 (list (car expr) (list 'neg (nth 1 expr)) (nth 2 expr))
1309 (if (eq (car-safe (nth 2 expr)) 'var)
1310 (list (car expr) (nth 1 expr) (list 'neg (nth 2 expr)))
1311 (math-neg expr)))
bf77c646 1312 (math-neg expr)))
136211a9
EZ
1313
1314(defun math-rwcomp-assoc-args (expr)
1315 (if (and (eq (car-safe (nth 1 expr)) (car expr))
1316 (= (length (nth 1 expr)) 3))
40ead937 1317 (math-rwcomp-assoc-args (nth 1 expr)))
136211a9
EZ
1318 (if (and (eq (car-safe (nth 2 expr)) (car expr))
1319 (= (length (nth 2 expr)) 3))
40ead937 1320 (math-rwcomp-assoc-args (nth 2 expr))))
136211a9
EZ
1321
1322(defun math-rwcomp-addsub-args (expr)
1323 (if (memq (car-safe (nth 1 expr)) '(+ -))
40ead937 1324 (math-rwcomp-addsub-args (nth 1 expr)))
136211a9 1325 (if (eq (car expr) '-)
40ead937 1326 ()
136211a9 1327 (if (eq (car-safe (nth 2 expr)) '+)
40ead937 1328 (math-rwcomp-addsub-args (nth 2 expr)))))
136211a9
EZ
1329
1330(defun math-rwcomp-order (a b)
1331 (< (math-rwcomp-priority (car a))
bf77c646 1332 (math-rwcomp-priority (car b))))
136211a9
EZ
1333
1334;;; Order of priority: 0 Constants and other exact matches (first)
1335;;; 10 Functions (except below)
1336;;; 20 Meta-variables which occur more than once
1337;;; 30 Algebraic functions
1338;;; 40 Commutative/associative functions
1339;;; 50 Meta-variables which occur only once
1340;;; +100 for every "!!!" (pnot) in the pattern
1341;;; 10000 Optional arguments (last)
1342
1343(defun math-rwcomp-priority (expr)
1344 (+ (math-rwcomp-count-pnots expr)
1345 (cond ((eq (car-safe expr) 'calcFunc-opt)
1346 10000)
1347 ((math-rwcomp-no-vars expr)
1348 0)
1349 ((eq (car expr) 'calcFunc-quote)
1350 0)
1351 ((eq (car expr) 'var)
1352 (if (assq (nth 2 expr) math-regs)
1353 0
1354 (if (= (math-rwcomp-count-refs expr) 1)
1355 50
1356 20)))
1357 (t (let ((props (get (car expr) 'math-rewrite-props)))
1358 (if (or (memq 'commut props)
1359 (memq 'assoc props))
1360 40
1361 (if (memq 'algebraic props)
1362 30
bf77c646 1363 10)))))))
136211a9
EZ
1364
1365(defun math-rwcomp-count-refs (var)
1366 (let ((count (or (math-expr-contains-count math-pattern var) 0))
1367 (p math-conds))
1368 (while p
1369 (if (eq (car-safe (car p)) 'calcFunc-let)
1370 (if (= (length (car p)) 3)
1371 (setq count (+ count
1372 (or (math-expr-contains-count (nth 2 (car p)) var)
1373 0)))
1374 (if (and (= (length (car p)) 2)
1375 (eq (car-safe (nth 1 (car p))) 'calcFunc-assign)
1376 (= (length (nth 1 (car p))) 3))
1377 (setq count (+ count
1378 (or (math-expr-contains-count
1379 (nth 2 (nth 1 (car p))) var) 0))))))
1380 (setq p (cdr p)))
bf77c646 1381 count))
136211a9
EZ
1382
1383(defun math-rwcomp-count-pnots (expr)
1384 (if (Math-primp expr)
1385 0
1386 (if (eq (car expr) 'calcFunc-pnot)
1387 100
1388 (let ((count 0))
1389 (while (setq expr (cdr expr))
1390 (setq count (+ count (math-rwcomp-count-pnots (car expr)))))
bf77c646 1391 count))))
136211a9
EZ
1392
1393;;; In the current implementation, all associative functions must
1394;;; also be commutative.
1395
1396(put '+ 'math-rewrite-props '(algebraic assoc commut))
1397(put '- 'math-rewrite-props '(algebraic assoc commut)) ; see below
1398(put '* 'math-rewrite-props '(algebraic assoc commut)) ; see below
1399(put '/ 'math-rewrite-props '(algebraic unary1))
1400(put '^ 'math-rewrite-props '(algebraic unary1))
1401(put '% 'math-rewrite-props '(algebraic))
1402(put 'neg 'math-rewrite-props '(algebraic))
1403(put 'calcFunc-idiv 'math-rewrite-props '(algebraic))
1404(put 'calcFunc-abs 'math-rewrite-props '(algebraic))
1405(put 'calcFunc-sign 'math-rewrite-props '(algebraic))
1406(put 'calcFunc-round 'math-rewrite-props '(algebraic))
1407(put 'calcFunc-rounde 'math-rewrite-props '(algebraic))
1408(put 'calcFunc-roundu 'math-rewrite-props '(algebraic))
1409(put 'calcFunc-trunc 'math-rewrite-props '(algebraic))
1410(put 'calcFunc-floor 'math-rewrite-props '(algebraic))
1411(put 'calcFunc-ceil 'math-rewrite-props '(algebraic))
1412(put 'calcFunc-re 'math-rewrite-props '(algebraic))
1413(put 'calcFunc-im 'math-rewrite-props '(algebraic))
1414(put 'calcFunc-conj 'math-rewrite-props '(algebraic))
1415(put 'calcFunc-arg 'math-rewrite-props '(algebraic))
1416(put 'calcFunc-and 'math-rewrite-props '(assoc commut))
1417(put 'calcFunc-or 'math-rewrite-props '(assoc commut))
1418(put 'calcFunc-xor 'math-rewrite-props '(assoc commut))
1419(put 'calcFunc-eq 'math-rewrite-props '(commut))
1420(put 'calcFunc-neq 'math-rewrite-props '(commut))
1421(put 'calcFunc-land 'math-rewrite-props '(assoc commut))
1422(put 'calcFunc-lor 'math-rewrite-props '(assoc commut))
1423(put 'calcFunc-beta 'math-rewrite-props '(commut))
1424(put 'calcFunc-gcd 'math-rewrite-props '(assoc commut))
1425(put 'calcFunc-lcm 'math-rewrite-props '(assoc commut))
1426(put 'calcFunc-max 'math-rewrite-props '(algebraic assoc commut))
1427(put 'calcFunc-min 'math-rewrite-props '(algebraic assoc commut))
1428(put 'calcFunc-vunion 'math-rewrite-props '(assoc commut))
1429(put 'calcFunc-vint 'math-rewrite-props '(assoc commut))
1430(put 'calcFunc-vxor 'math-rewrite-props '(assoc commut))
1431
1432;;; Note: "*" is not commutative for matrix args, but we pretend it is.
1433;;; Also, "-" is not commutative but the code tweaks things so that it is.
1434
1435(put '+ 'math-rewrite-default 0)
1436(put '- 'math-rewrite-default 0)
1437(put '* 'math-rewrite-default 1)
1438(put '/ 'math-rewrite-default 1)
1439(put '^ 'math-rewrite-default 1)
1440(put 'calcFunc-land 'math-rewrite-default 1)
1441(put 'calcFunc-lor 'math-rewrite-default 0)
1442(put 'calcFunc-vunion 'math-rewrite-default '(vec))
1443(put 'calcFunc-vint 'math-rewrite-default '(vec))
1444(put 'calcFunc-vdiff 'math-rewrite-default '(vec))
1445(put 'calcFunc-vxor 'math-rewrite-default '(vec))
1446
1447(defmacro math-rwfail (&optional back)
1448 (list 'setq 'pc
1449 (list 'and
1450 (if back
1451 '(setq btrack (cdr btrack))
1452 'btrack)
bf77c646 1453 ''((backtrack)))))
136211a9
EZ
1454
1455;;; This monstrosity is necessary because the use of static vectors of
1456;;; registers makes rewrite rules non-reentrant. Yucko!
1457(defmacro math-rweval (form)
1458 (list 'let '((orig (car rules)))
1459 '(setcar rules (quote (nil nil nil no-phase)))
1460 (list 'unwind-protect
1461 form
bf77c646 1462 '(setcar rules orig))))
136211a9 1463
40ead937
JB
1464(defvar math-rewrite-phase 1)
1465
1466;; The variable math-apply-rw-regs is local to math-apply-rewrites,
1467;; but is used by math-rwapply-replace-regs and math-rwapply-reg-looks-negp
1468;; which are called by math-apply-rewrites.
1469(defvar math-apply-rw-regs)
136211a9 1470
40ead937
JB
1471;; The variable math-apply-rw-ruleset is local to math-apply-rewrites,
1472;; but is used by math-rwapply-remember.
1473(defvar math-apply-rw-ruleset)
1474
1475(defun math-apply-rewrites (expr rules &optional heads math-apply-rw-ruleset)
136211a9
EZ
1476 (and
1477 (setq rules (cdr (or (assq (car-safe expr) rules)
1478 (assq nil rules))))
1479 (let ((result nil)
40ead937 1480 op math-apply-rw-regs inst part pc mark btrack
136211a9
EZ
1481 (tracing math-rwcomp-tracing)
1482 (phase math-rewrite-phase))
1483 (while rules
1484 (or
1485 (and (setq part (nth 2 (car rules)))
1486 heads
1487 (not (memq part heads)))
1488 (and (setq part (nth 3 (car rules)))
1489 (not (memq phase part)))
1490 (progn
40ead937 1491 (setq math-apply-rw-regs (car (car rules))
136211a9
EZ
1492 pc (nth 1 (car rules))
1493 btrack nil)
40ead937 1494 (aset math-apply-rw-regs 0 expr)
136211a9 1495 (while pc
a1506d29 1496
136211a9
EZ
1497 (and tracing
1498 (progn (terpri) (princ (car pc))
1499 (if (and (natnump (nth 1 (car pc)))
40ead937
JB
1500 (< (nth 1 (car pc)) (length math-apply-rw-regs)))
1501 (princ
1502 (format "\n part = %s"
1503 (aref math-apply-rw-regs (nth 1 (car pc))))))))
a1506d29 1504
136211a9 1505 (cond ((eq (setq op (car (setq inst (car pc)))) 'func)
40ead937
JB
1506 (if (and (consp
1507 (setq part (aref math-apply-rw-regs (car (cdr inst)))))
136211a9
EZ
1508 (eq (car part)
1509 (car (setq inst (cdr (cdr inst)))))
1510 (progn
1511 (while (and (setq inst (cdr inst)
1512 part (cdr part))
1513 inst)
40ead937 1514 (aset math-apply-rw-regs (car inst) (car part)))
136211a9
EZ
1515 (not (or inst part))))
1516 (setq pc (cdr pc))
1517 (math-rwfail)))
a1506d29 1518
136211a9 1519 ((eq op 'same)
40ead937
JB
1520 (if (or (equal (setq part (aref math-apply-rw-regs (nth 1 inst)))
1521 (setq mark (aref math-apply-rw-regs (nth 2 inst))))
136211a9
EZ
1522 (Math-equal part mark))
1523 (setq pc (cdr pc))
1524 (math-rwfail)))
a1506d29 1525
136211a9
EZ
1526 ((and (eq op 'try)
1527 calc-matrix-mode
1528 (not (eq calc-matrix-mode 'scalar))
1529 (eq (car (nth 2 inst)) '*)
40ead937 1530 (consp (setq part (aref math-apply-rw-regs (car (cdr inst)))))
136211a9
EZ
1531 (eq (car part) '*)
1532 (not (math-known-scalarp part)))
1533 (setq mark (nth 3 inst)
1534 pc (cdr pc))
1535 (if (aref mark 4)
1536 (progn
40ead937 1537 (aset math-apply-rw-regs (nth 4 inst) (nth 2 part))
136211a9 1538 (aset mark 1 (cdr (cdr part))))
40ead937 1539 (aset math-apply-rw-regs (nth 4 inst) (nth 1 part))
136211a9
EZ
1540 (aset mark 1 (cdr part)))
1541 (aset mark 0 (cdr part))
1542 (aset mark 2 0))
a1506d29 1543
136211a9 1544 ((eq op 'try)
40ead937
JB
1545 (if (and (consp (setq part
1546 (aref math-apply-rw-regs (car (cdr inst)))))
136211a9
EZ
1547 (memq (car part) (nth 2 inst))
1548 (= (length part) 3)
1549 (or (not (eq (car part) '/))
1550 (Math-objectp (nth 2 part))))
1551 (progn
1552 (setq op nil
1553 mark (car (cdr (setq inst (cdr (cdr inst))))))
1554 (and
1555 (memq 'assoc (get (car part) 'math-rewrite-props))
1556 (not (= (aref mark 3) 0))
1557 (while (if (and (consp (nth 1 part))
1558 (memq (car (nth 1 part)) (car inst)))
1559 (setq op (cons (if (eq (car part) '-)
1560 (math-rwapply-neg
1561 (nth 2 part))
1562 (nth 2 part))
1563 op)
1564 part (nth 1 part))
1565 (if (and (consp (nth 2 part))
1566 (memq (car (nth 2 part))
1567 (car inst))
1568 (not (eq (car (nth 2 part)) '-)))
1569 (setq op (cons (nth 1 part) op)
1570 part (nth 2 part))))))
1571 (setq op (cons (nth 1 part)
1572 (cons (if (eq (car part) '-)
1573 (math-rwapply-neg
1574 (nth 2 part))
1575 (if (eq (car part) '/)
1576 (math-rwapply-inv
1577 (nth 2 part))
1578 (nth 2 part)))
1579 op))
1580 btrack (cons pc btrack)
1581 pc (cdr pc))
40ead937 1582 (aset math-apply-rw-regs (nth 2 inst) (car op))
136211a9
EZ
1583 (aset mark 0 op)
1584 (aset mark 1 op)
1585 (aset mark 2 (if (cdr (cdr op)) 1 0)))
1586 (if (nth 5 inst)
1587 (if (and (consp part)
1588 (eq (car part) 'neg)
1589 (eq (car (nth 2 inst)) '*)
1590 (eq (nth 5 inst) 1))
1591 (progn
1592 (setq mark (nth 3 inst)
1593 pc (cdr pc))
40ead937 1594 (aset math-apply-rw-regs (nth 4 inst) (nth 1 part))
136211a9
EZ
1595 (aset mark 1 -1)
1596 (aset mark 2 4))
1597 (setq mark (nth 3 inst)
1598 pc (cdr pc))
40ead937 1599 (aset math-apply-rw-regs (nth 4 inst) part)
136211a9
EZ
1600 (aset mark 2 3))
1601 (math-rwfail))))
a1506d29 1602
136211a9
EZ
1603 ((eq op 'try2)
1604 (setq part (nth 1 inst) ; try instr
1605 mark (nth 3 part)
1606 op (aref mark 2)
1607 pc (cdr pc))
40ead937 1608 (aset math-apply-rw-regs (nth 2 inst)
136211a9
EZ
1609 (cond
1610 ((eq op 0)
1611 (if (eq (aref mark 0) (aref mark 1))
1612 (nth 1 (aref mark 0))
1613 (car (aref mark 0))))
1614 ((eq op 1)
1615 (setq mark (delq (car (aref mark 1))
1616 (copy-sequence (aref mark 0)))
1617 op (car (nth 2 part)))
1618 (if (eq op '*)
1619 (progn
1620 (setq mark (nreverse mark)
1621 part (list '* (nth 1 mark) (car mark))
1622 mark (cdr mark))
1623 (while (setq mark (cdr mark))
1624 (setq part (list '* (car mark) part))))
1625 (setq part (car mark)
1626 mark (cdr mark)
1627 part (if (and (eq op '+)
1628 (consp (car mark))
1629 (eq (car (car mark)) 'neg))
1630 (list '- part
1631 (nth 1 (car mark)))
1632 (list op part (car mark))))
1633 (while (setq mark (cdr mark))
1634 (setq part (if (and (eq op '+)
1635 (consp (car mark))
1636 (eq (car (car mark)) 'neg))
1637 (list '- part
1638 (nth 1 (car mark)))
1639 (list op part (car mark))))))
1640 part)
1641 ((eq op 2)
1642 (car (aref mark 1)))
1643 ((eq op 3) (nth 5 part))
1644 (t (aref mark 1)))))
a1506d29 1645
136211a9
EZ
1646 ((eq op 'select)
1647 (setq pc (cdr pc))
40ead937 1648 (if (and (consp (setq part (aref math-apply-rw-regs (nth 1 inst))))
136211a9 1649 (eq (car part) 'calcFunc-select))
40ead937 1650 (aset math-apply-rw-regs (nth 2 inst) (nth 1 part))
136211a9
EZ
1651 (if math-rewrite-selections
1652 (math-rwfail)
40ead937 1653 (aset math-apply-rw-regs (nth 2 inst) part))))
a1506d29 1654
136211a9 1655 ((eq op 'same-neg)
40ead937 1656 (if (or (equal (setq part (aref math-apply-rw-regs (nth 1 inst)))
136211a9 1657 (setq mark (math-neg
40ead937 1658 (aref math-apply-rw-regs (nth 2 inst)))))
136211a9
EZ
1659 (Math-equal part mark))
1660 (setq pc (cdr pc))
1661 (math-rwfail)))
a1506d29 1662
136211a9
EZ
1663 ((eq op 'backtrack)
1664 (setq inst (car (car btrack)) ; "try" or "alt" instr
1665 pc (cdr (car btrack))
1666 mark (or (nth 3 inst) [nil nil 4])
1667 op (aref mark 2))
1668 (cond ((eq op 0)
1669 (if (setq op (cdr (aref mark 1)))
40ead937
JB
1670 (aset math-apply-rw-regs (nth 4 inst)
1671 (car (aset mark 1 op)))
136211a9
EZ
1672 (if (nth 5 inst)
1673 (progn
1674 (aset mark 2 3)
40ead937
JB
1675 (aset math-apply-rw-regs (nth 4 inst)
1676 (aref math-apply-rw-regs (nth 1 inst))))
136211a9
EZ
1677 (math-rwfail t))))
1678 ((eq op 1)
1679 (if (setq op (cdr (aref mark 1)))
40ead937
JB
1680 (aset math-apply-rw-regs (nth 4 inst)
1681 (car (aset mark 1 op)))
136211a9
EZ
1682 (if (= (aref mark 3) 1)
1683 (if (nth 5 inst)
1684 (progn
1685 (aset mark 2 3)
40ead937
JB
1686 (aset math-apply-rw-regs (nth 4 inst)
1687 (aref math-apply-rw-regs (nth 1 inst))))
136211a9
EZ
1688 (math-rwfail t))
1689 (aset mark 2 2)
1690 (aset mark 1 (cons nil (aref mark 0)))
1691 (math-rwfail))))
1692 ((eq op 2)
1693 (if (setq op (cdr (aref mark 1)))
1694 (progn
1695 (setq mark (delq (car (aset mark 1 op))
1696 (copy-sequence
1697 (aref mark 0)))
1698 op (car (nth 2 inst)))
1699 (if (eq op '*)
1700 (progn
1701 (setq mark (nreverse mark)
1702 part (list '* (nth 1 mark)
1703 (car mark))
1704 mark (cdr mark))
1705 (while (setq mark (cdr mark))
1706 (setq part (list '* (car mark)
1707 part))))
1708 (setq part (car mark)
1709 mark (cdr mark)
1710 part (if (and (eq op '+)
1711 (consp (car mark))
1712 (eq (car (car mark))
1713 'neg))
1714 (list '- part
1715 (nth 1 (car mark)))
1716 (list op part (car mark))))
1717 (while (setq mark (cdr mark))
1718 (setq part (if (and (eq op '+)
1719 (consp (car mark))
1720 (eq (car (car mark))
1721 'neg))
1722 (list '- part
1723 (nth 1 (car mark)))
1724 (list op part (car mark))))))
40ead937 1725 (aset math-apply-rw-regs (nth 4 inst) part))
136211a9
EZ
1726 (if (nth 5 inst)
1727 (progn
1728 (aset mark 2 3)
40ead937
JB
1729 (aset math-apply-rw-regs (nth 4 inst)
1730 (aref math-apply-rw-regs (nth 1 inst))))
136211a9
EZ
1731 (math-rwfail t))))
1732 ((eq op 4)
1733 (setq btrack (cdr btrack)))
1734 (t (math-rwfail t))))
a1506d29 1735
136211a9 1736 ((eq op 'integer)
40ead937
JB
1737 (if (Math-integerp (setq part
1738 (aref math-apply-rw-regs (nth 1 inst))))
136211a9
EZ
1739 (setq pc (cdr pc))
1740 (if (Math-primp part)
1741 (math-rwfail)
1742 (setq part (math-rweval (math-simplify part)))
1743 (if (Math-integerp part)
1744 (setq pc (cdr pc))
1745 (math-rwfail)))))
a1506d29 1746
136211a9 1747 ((eq op 'real)
40ead937 1748 (if (Math-realp (setq part (aref math-apply-rw-regs (nth 1 inst))))
136211a9
EZ
1749 (setq pc (cdr pc))
1750 (if (Math-primp part)
1751 (math-rwfail)
1752 (setq part (math-rweval (math-simplify part)))
1753 (if (Math-realp part)
1754 (setq pc (cdr pc))
1755 (math-rwfail)))))
a1506d29 1756
136211a9 1757 ((eq op 'constant)
40ead937 1758 (if (math-constp (setq part (aref math-apply-rw-regs (nth 1 inst))))
136211a9
EZ
1759 (setq pc (cdr pc))
1760 (if (Math-primp part)
1761 (math-rwfail)
1762 (setq part (math-rweval (math-simplify part)))
1763 (if (math-constp part)
1764 (setq pc (cdr pc))
1765 (math-rwfail)))))
a1506d29 1766
136211a9 1767 ((eq op 'negative)
40ead937
JB
1768 (if (math-looks-negp (setq part
1769 (aref math-apply-rw-regs (nth 1 inst))))
136211a9
EZ
1770 (setq pc (cdr pc))
1771 (if (Math-primp part)
1772 (math-rwfail)
1773 (setq part (math-rweval (math-simplify part)))
1774 (if (math-looks-negp part)
1775 (setq pc (cdr pc))
1776 (math-rwfail)))))
a1506d29 1777
136211a9 1778 ((eq op 'rel)
40ead937
JB
1779 (setq part (math-compare (aref math-apply-rw-regs (nth 1 inst))
1780 (aref math-apply-rw-regs (nth 3 inst)))
136211a9
EZ
1781 op (nth 2 inst))
1782 (if (= part 2)
1783 (setq part (math-rweval
1784 (math-simplify
1785 (calcFunc-sign
40ead937
JB
1786 (math-sub
1787 (aref math-apply-rw-regs (nth 1 inst))
1788 (aref math-apply-rw-regs (nth 3 inst))))))))
136211a9
EZ
1789 (if (cond ((eq op 'calcFunc-eq)
1790 (eq part 0))
1791 ((eq op 'calcFunc-neq)
1792 (memq part '(-1 1)))
1793 ((eq op 'calcFunc-lt)
1794 (eq part -1))
1795 ((eq op 'calcFunc-leq)
1796 (memq part '(-1 0)))
1797 ((eq op 'calcFunc-gt)
1798 (eq part 1))
1799 ((eq op 'calcFunc-geq)
1800 (memq part '(0 1))))
1801 (setq pc (cdr pc))
1802 (math-rwfail)))
a1506d29 1803
136211a9 1804 ((eq op 'func-def)
40ead937
JB
1805 (if (and
1806 (consp (setq part (aref math-apply-rw-regs (car (cdr inst)))))
1807 (eq (car part)
1808 (car (setq inst (cdr (cdr inst))))))
136211a9
EZ
1809 (progn
1810 (setq inst (cdr inst)
1811 mark (car inst))
1812 (while (and (setq inst (cdr inst)
1813 part (cdr part))
1814 inst)
40ead937 1815 (aset math-apply-rw-regs (car inst) (car part)))
136211a9
EZ
1816 (if (or inst part)
1817 (setq pc (cdr pc))
1818 (while (eq (car (car (setq pc (cdr pc))))
1819 'func-def))
1820 (setq pc (cdr pc)) ; skip over "func"
1821 (while mark
40ead937 1822 (aset math-apply-rw-regs (cdr (car mark)) (car (car mark)))
136211a9
EZ
1823 (setq mark (cdr mark)))))
1824 (math-rwfail)))
1825
1826 ((eq op 'func-opt)
40ead937
JB
1827 (if (or (not
1828 (and
1829 (consp
1830 (setq part (aref math-apply-rw-regs (car (cdr inst)))))
1831 (eq (car part) (nth 2 inst))))
136211a9
EZ
1832 (and (= (length part) 2)
1833 (setq part (nth 1 part))))
1834 (progn
1835 (setq mark (nth 3 inst))
40ead937 1836 (aset math-apply-rw-regs (nth 4 inst) part)
136211a9
EZ
1837 (while (eq (car (car (setq pc (cdr pc)))) 'func-def))
1838 (setq pc (cdr pc)) ; skip over "func"
1839 (while mark
40ead937 1840 (aset math-apply-rw-regs (cdr (car mark)) (car (car mark)))
136211a9
EZ
1841 (setq mark (cdr mark))))
1842 (setq pc (cdr pc))))
1843
1844 ((eq op 'mod)
40ead937
JB
1845 (if (if (Math-zerop
1846 (setq part (aref math-apply-rw-regs (nth 1 inst))))
136211a9
EZ
1847 (Math-zerop (nth 3 inst))
1848 (and (not (Math-zerop (nth 2 inst)))
1849 (progn
1850 (setq part (math-mod part (nth 2 inst)))
1851 (or (Math-numberp part)
1852 (setq part (math-rweval
1853 (math-simplify part))))
1854 (Math-equal part (nth 3 inst)))))
1855 (setq pc (cdr pc))
1856 (math-rwfail)))
1857
1858 ((eq op 'apply)
40ead937
JB
1859 (if (and (consp
1860 (setq part (aref math-apply-rw-regs (car (cdr inst)))))
136211a9
EZ
1861 (not (Math-objvecp part))
1862 (not (eq (car part) 'var)))
1863 (progn
40ead937 1864 (aset math-apply-rw-regs (nth 2 inst)
136211a9 1865 (math-calcFunc-to-var (car part)))
40ead937 1866 (aset math-apply-rw-regs (nth 3 inst)
136211a9
EZ
1867 (cons 'vec (cdr part)))
1868 (setq pc (cdr pc)))
1869 (math-rwfail)))
1870
1871 ((eq op 'cons)
40ead937
JB
1872 (if (and (consp
1873 (setq part (aref math-apply-rw-regs (car (cdr inst)))))
136211a9
EZ
1874 (eq (car part) 'vec)
1875 (cdr part))
1876 (progn
40ead937
JB
1877 (aset math-apply-rw-regs (nth 2 inst) (nth 1 part))
1878 (aset math-apply-rw-regs (nth 3 inst)
1879 (cons 'vec (cdr (cdr part))))
136211a9
EZ
1880 (setq pc (cdr pc)))
1881 (math-rwfail)))
1882
1883 ((eq op 'rcons)
40ead937
JB
1884 (if (and (consp
1885 (setq part (aref math-apply-rw-regs (car (cdr inst)))))
136211a9
EZ
1886 (eq (car part) 'vec)
1887 (cdr part))
1888 (progn
40ead937
JB
1889 (aset math-apply-rw-regs (nth 2 inst) (calcFunc-rhead part))
1890 (aset math-apply-rw-regs (nth 3 inst) (calcFunc-rtail part))
136211a9
EZ
1891 (setq pc (cdr pc)))
1892 (math-rwfail)))
1893
1894 ((eq op 'cond)
1895 (if (math-is-true
1896 (math-rweval
1897 (math-simplify
1898 (math-rwapply-replace-regs (nth 1 inst)))))
1899 (setq pc (cdr pc))
1900 (math-rwfail)))
a1506d29 1901
136211a9 1902 ((eq op 'let)
40ead937 1903 (aset math-apply-rw-regs (nth 1 inst)
136211a9
EZ
1904 (math-rweval
1905 (math-normalize
1906 (math-rwapply-replace-regs (nth 2 inst)))))
1907 (setq pc (cdr pc)))
a1506d29 1908
136211a9 1909 ((eq op 'copy)
40ead937
JB
1910 (aset math-apply-rw-regs (nth 2 inst)
1911 (aref math-apply-rw-regs (nth 1 inst)))
136211a9 1912 (setq pc (cdr pc)))
a1506d29 1913
136211a9 1914 ((eq op 'copy-neg)
40ead937
JB
1915 (aset math-apply-rw-regs (nth 2 inst)
1916 (math-rwapply-neg (aref math-apply-rw-regs (nth 1 inst))))
136211a9 1917 (setq pc (cdr pc)))
a1506d29 1918
136211a9
EZ
1919 ((eq op 'alt)
1920 (setq btrack (cons pc btrack)
1921 pc (nth 1 inst)))
a1506d29 1922
136211a9
EZ
1923 ((eq op 'end-alt)
1924 (while (and btrack (not (eq (car btrack) (nth 1 inst))))
1925 (setq btrack (cdr btrack)))
1926 (setq btrack (cdr btrack)
1927 pc (cdr pc)))
a1506d29 1928
136211a9
EZ
1929 ((eq op 'done)
1930 (setq result (math-rwapply-replace-regs (nth 1 inst)))
1931 (if (or (and (eq (car-safe result) '+)
1932 (eq (nth 2 result) 0))
1933 (and (eq (car-safe result) '*)
1934 (eq (nth 2 result) 1)))
1935 (setq result (nth 1 result)))
1936 (setq part (and (nth 2 inst)
1937 (math-is-true
1938 (math-rweval
1939 (math-simplify
1940 (math-rwapply-replace-regs
1941 (nth 2 inst)))))))
1942 (if (or (equal result expr)
1943 (equal (setq result (math-normalize result)) expr))
1944 (setq result nil)
1945 (if part (math-rwapply-remember expr result))
1946 (setq rules nil))
1947 (setq pc nil))
a1506d29 1948
136211a9
EZ
1949 (t (error "%s is not a valid rewrite opcode" op))))))
1950 (setq rules (cdr rules)))
bf77c646 1951 result)))
136211a9
EZ
1952
1953(defun math-rwapply-neg (expr)
1954 (if (and (consp expr)
1955 (memq (car expr) '(* /)))
1956 (if (Math-objectp (nth 2 expr))
1957 (list (car expr) (nth 1 expr) (math-neg (nth 2 expr)))
1958 (list (car expr)
1959 (if (Math-objectp (nth 1 expr))
1960 (math-neg (nth 1 expr))
1961 (list '* -1 (nth 1 expr)))
1962 (nth 2 expr)))
bf77c646 1963 (math-neg expr)))
136211a9
EZ
1964
1965(defun math-rwapply-inv (expr)
1966 (if (and (Math-integerp expr)
1967 calc-prefer-frac)
1968 (math-make-frac 1 expr)
bf77c646 1969 (list '/ 1 expr)))
136211a9
EZ
1970
1971(defun math-rwapply-replace-regs (expr)
1972 (cond ((Math-primp expr)
1973 expr)
1974 ((eq (car expr) 'calcFunc-register)
40ead937 1975 (setq expr (aref math-apply-rw-regs (nth 1 expr)))
136211a9
EZ
1976 (if (eq (car-safe expr) '*)
1977 (if (eq (nth 1 expr) -1)
1978 (math-neg (nth 2 expr))
1979 (if (eq (nth 1 expr) 1)
1980 (nth 2 expr)
1981 expr))
1982 expr))
1983 ((and (eq (car expr) 'calcFunc-eval)
1984 (= (length expr) 2))
1985 (calc-with-default-simplification
1986 (math-normalize (math-rwapply-replace-regs (nth 1 expr)))))
1987 ((and (eq (car expr) 'calcFunc-evalsimp)
1988 (= (length expr) 2))
1989 (math-simplify (math-rwapply-replace-regs (nth 1 expr))))
1990 ((and (eq (car expr) 'calcFunc-evalextsimp)
1991 (= (length expr) 2))
1992 (math-simplify-extended (math-rwapply-replace-regs (nth 1 expr))))
1993 ((and (eq (car expr) 'calcFunc-apply)
1994 (= (length expr) 3))
1995 (let ((func (math-rwapply-replace-regs (nth 1 expr)))
1996 (args (math-rwapply-replace-regs (nth 2 expr)))
1997 call)
1998 (if (and (math-vectorp args)
1999 (not (eq (car-safe (setq call (math-build-call
2000 (math-var-to-calcFunc func)
2001 (cdr args))))
2002 'calcFunc-call)))
2003 call
2004 (list 'calcFunc-apply func args))))
2005 ((and (eq (car expr) 'calcFunc-cons)
2006 (= (length expr) 3))
2007 (let ((head (math-rwapply-replace-regs (nth 1 expr)))
2008 (tail (math-rwapply-replace-regs (nth 2 expr))))
2009 (if (math-vectorp tail)
2010 (cons 'vec (cons head (cdr tail)))
2011 (list 'calcFunc-cons head tail))))
2012 ((and (eq (car expr) 'calcFunc-rcons)
2013 (= (length expr) 3))
2014 (let ((head (math-rwapply-replace-regs (nth 1 expr)))
2015 (tail (math-rwapply-replace-regs (nth 2 expr))))
2016 (if (math-vectorp head)
2017 (append head (list tail))
2018 (list 'calcFunc-rcons head tail))))
2019 ((and (eq (car expr) 'neg)
2020 (math-rwapply-reg-looks-negp (nth 1 expr)))
2021 (math-rwapply-reg-neg (nth 1 expr)))
2022 ((and (eq (car expr) 'neg)
2023 (eq (car-safe (nth 1 expr)) 'calcFunc-register)
40ead937 2024 (math-scalarp (aref math-apply-rw-regs (nth 1 (nth 1 expr)))))
136211a9
EZ
2025 (math-neg (math-rwapply-replace-regs (nth 1 expr))))
2026 ((and (eq (car expr) '+)
2027 (math-rwapply-reg-looks-negp (nth 1 expr)))
2028 (list '- (math-rwapply-replace-regs (nth 2 expr))
2029 (math-rwapply-reg-neg (nth 1 expr))))
2030 ((and (eq (car expr) '+)
2031 (math-rwapply-reg-looks-negp (nth 2 expr)))
2032 (list '- (math-rwapply-replace-regs (nth 1 expr))
2033 (math-rwapply-reg-neg (nth 2 expr))))
2034 ((and (eq (car expr) '-)
2035 (math-rwapply-reg-looks-negp (nth 2 expr)))
2036 (list '+ (math-rwapply-replace-regs (nth 1 expr))
2037 (math-rwapply-reg-neg (nth 2 expr))))
2038 ((eq (car expr) '*)
2039 (cond ((eq (nth 1 expr) -1)
2040 (if (math-rwapply-reg-looks-negp (nth 2 expr))
2041 (math-rwapply-reg-neg (nth 2 expr))
2042 (math-neg (math-rwapply-replace-regs (nth 2 expr)))))
2043 ((eq (nth 1 expr) 1)
2044 (math-rwapply-replace-regs (nth 2 expr)))
2045 ((eq (nth 2 expr) -1)
2046 (if (math-rwapply-reg-looks-negp (nth 1 expr))
2047 (math-rwapply-reg-neg (nth 1 expr))
2048 (math-neg (math-rwapply-replace-regs (nth 1 expr)))))
2049 ((eq (nth 2 expr) 1)
2050 (math-rwapply-replace-regs (nth 1 expr)))
2051 (t
2052 (let ((arg1 (math-rwapply-replace-regs (nth 1 expr)))
2053 (arg2 (math-rwapply-replace-regs (nth 2 expr))))
2054 (cond ((and (eq (car-safe arg1) '/)
2055 (eq (nth 1 arg1) 1))
2056 (list '/ arg2 (nth 2 arg1)))
2057 ((and (eq (car-safe arg2) '/)
2058 (eq (nth 1 arg2) 1))
2059 (list '/ arg1 (nth 2 arg2)))
2060 (t (list '* arg1 arg2)))))))
2061 ((eq (car expr) '/)
2062 (let ((arg1 (math-rwapply-replace-regs (nth 1 expr)))
2063 (arg2 (math-rwapply-replace-regs (nth 2 expr))))
2064 (if (eq (car-safe arg2) '/)
2065 (list '/ (list '* arg1 (nth 2 arg2)) (nth 1 arg2))
2066 (list '/ arg1 arg2))))
2067 ((and (eq (car expr) 'calcFunc-plain)
2068 (= (length expr) 2))
2069 (if (Math-primp (nth 1 expr))
2070 (nth 1 expr)
2071 (if (eq (car (nth 1 expr)) 'calcFunc-register)
40ead937 2072 (aref math-apply-rw-regs (nth 1 (nth 1 expr)))
136211a9
EZ
2073 (cons (car (nth 1 expr)) (mapcar 'math-rwapply-replace-regs
2074 (cdr (nth 1 expr)))))))
bf77c646 2075 (t (cons (car expr) (mapcar 'math-rwapply-replace-regs (cdr expr))))))
136211a9
EZ
2076
2077(defun math-rwapply-reg-looks-negp (expr)
2078 (if (eq (car-safe expr) 'calcFunc-register)
40ead937 2079 (math-looks-negp (aref math-apply-rw-regs (nth 1 expr)))
136211a9
EZ
2080 (if (memq (car-safe expr) '(* /))
2081 (or (math-rwapply-reg-looks-negp (nth 1 expr))
bf77c646 2082 (math-rwapply-reg-looks-negp (nth 2 expr))))))
136211a9
EZ
2083
2084(defun math-rwapply-reg-neg (expr) ; expr must satisfy rwapply-reg-looks-negp
2085 (if (eq (car expr) 'calcFunc-register)
2086 (math-neg (math-rwapply-replace-regs expr))
2087 (if (math-rwapply-reg-looks-negp (nth 1 expr))
2088 (math-rwapply-replace-regs (list (car expr)
2089 (math-rwapply-reg-neg (nth 1 expr))
2090 (nth 2 expr)))
2091 (math-rwapply-replace-regs (list (car expr)
2092 (nth 1 expr)
bf77c646 2093 (math-rwapply-reg-neg (nth 2 expr)))))))
136211a9
EZ
2094
2095(defun math-rwapply-remember (old new)
40ead937
JB
2096 (let ((varval (symbol-value (nth 2 (car math-apply-rw-ruleset))))
2097 (rules (assq (car-safe old) math-apply-rw-ruleset)))
136211a9
EZ
2098 (if (and (eq (car-safe varval) 'vec)
2099 (not (memq (car-safe old) '(nil schedule + -)))
2100 rules)
2101 (progn
2102 (setcdr varval (cons (list 'calcFunc-assign
2103 (if (math-rwcomp-no-vars old)
2104 old
2105 (list 'calcFunc-quote old))
2106 new)
2107 (cdr varval)))
2108 (setcdr rules (cons (list (vector nil old)
2109 (list (list 'same 0 1)
2110 (list 'done new nil))
2111 nil nil)
bf77c646 2112 (cdr rules)))))))
136211a9 2113
a2470ec9
JB
2114(provide 'calc-rewr)
2115
cbee283d 2116;; arch-tag: ca8d7b7d-bff1-4535-90f3-e2241f5e786b
bf77c646 2117;;; calc-rewr.el ends here