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