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