summaryrefslogtreecommitdiff
path: root/lisp/calc/calc-rewr.el
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2001-11-06 18:59:06 +0000
committerEli Zaretskii <eliz@gnu.org>2001-11-06 18:59:06 +0000
commit136211a997eb94f7dc6f97219052317116e114da (patch)
tree014fd8ffa0fa5c5d81869ec26426fb262471ee23 /lisp/calc/calc-rewr.el
parent0ffbbdeb4464b5b0d63e83fe3f8e91674248d84d (diff)
downloademacs-136211a997eb94f7dc6f97219052317116e114da.tar.gz
Initial import of Calc 2.02f.
Diffstat (limited to 'lisp/calc/calc-rewr.el')
-rw-r--r--lisp/calc/calc-rewr.el2097
1 files changed, 2097 insertions, 0 deletions
diff --git a/lisp/calc/calc-rewr.el b/lisp/calc/calc-rewr.el
new file mode 100644
index 00000000000..4250533f623
--- /dev/null
+++ b/lisp/calc/calc-rewr.el
@@ -0,0 +1,2097 @@
+;; Calculator for GNU Emacs, part II [calc-rewr.el]
+;; Copyright (C) 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+;; Written by Dave Gillespie, daveg@synaptics.com.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY. No author or distributor
+;; accepts responsibility to anyone for the consequences of using it
+;; or for whether it serves any particular purpose or works at all,
+;; unless he says so in writing. Refer to the GNU Emacs General Public
+;; License for full details.
+
+;; Everyone is granted permission to copy, modify and redistribute
+;; GNU Emacs, but only under the conditions described in the
+;; GNU Emacs General Public License. A copy of this license is
+;; supposed to have been given to you along with GNU Emacs so you
+;; can know your rights and responsibilities. It should be in a
+;; file named COPYING. Among other things, the copyright notice
+;; and this notice must be preserved on all copies.
+
+
+
+;; This file is autoloaded from calc-ext.el.
+(require 'calc-ext)
+
+(require 'calc-macs)
+
+(defun calc-Need-calc-rewr () nil)
+
+
+(defun calc-rewrite-selection (rules-str &optional many prefix)
+ (interactive "sRewrite rule(s): \np")
+ (calc-slow-wrapper
+ (calc-preserve-point)
+ (let* ((num (max 1 (calc-locate-cursor-element (point))))
+ (reselect t)
+ (pop-rules nil)
+ (entry (calc-top num 'entry))
+ (expr (car entry))
+ (sel (calc-auto-selection entry))
+ (math-rewrite-selections t)
+ (math-rewrite-default-iters 1))
+ (if (or (null rules-str) (equal rules-str "") (equal rules-str "$"))
+ (if (= num 1)
+ (error "Can't use same stack entry for formula and rules.")
+ (setq rules (calc-top-n 1 t)
+ pop-rules t))
+ (setq rules (if (stringp rules-str)
+ (math-read-exprs rules-str) rules-str))
+ (if (eq (car-safe rules) 'error)
+ (error "Bad format in expression: %s" (nth 1 rules)))
+ (if (= (length rules) 1)
+ (setq rules (car rules))
+ (setq rules (cons 'vec rules)))
+ (or (memq (car-safe rules) '(vec var calcFunc-assign
+ calcFunc-condition))
+ (let ((rhs (math-read-expr
+ (read-string (concat "Rewrite from: " rules-str
+ " to: ")))))
+ (if (eq (car-safe rhs) 'error)
+ (error "Bad format in expression: %s" (nth 1 rhs)))
+ (setq rules (list 'calcFunc-assign rules rhs))))
+ (or (eq (car-safe rules) 'var)
+ (calc-record rules "rule")))
+ (if (eq many 0)
+ (setq many '(var inf var-inf))
+ (if many (setq many (prefix-numeric-value many))))
+ (if sel
+ (setq expr (calc-replace-sub-formula (car entry)
+ sel
+ (list 'calcFunc-select sel)))
+ (setq expr (car entry)
+ reselect nil
+ math-rewrite-selections nil))
+ (setq expr (calc-encase-atoms
+ (calc-normalize
+ (math-rewrite
+ (calc-normalize expr)
+ rules many)))
+ sel nil
+ expr (calc-locate-select-marker expr))
+ (or (consp sel) (setq sel nil))
+ (if pop-rules (calc-pop-stack 1))
+ (calc-pop-push-record-list 1 (or prefix "rwrt") (list expr)
+ (- num (if pop-rules 1 0))
+ (list (and reselect sel))))
+ (calc-handle-whys))
+)
+
+(defun calc-locate-select-marker (expr) ; changes "sel"
+ (if (Math-primp expr)
+ expr
+ (if (and (eq (car expr) 'calcFunc-select)
+ (= (length expr) 2))
+ (progn
+ (setq sel (if sel t (nth 1 expr)))
+ (nth 1 expr))
+ (cons (car expr)
+ (mapcar 'calc-locate-select-marker (cdr expr)))))
+)
+
+
+
+(defun calc-rewrite (rules-str many)
+ (interactive "sRewrite rule(s): \nP")
+ (calc-slow-wrapper
+ (let (n rules expr)
+ (if (or (null rules-str) (equal rules-str "") (equal rules-str "$"))
+ (setq expr (calc-top-n 2)
+ rules (calc-top-n 1 t)
+ n 2)
+ (setq rules (if (stringp rules-str)
+ (math-read-exprs rules-str) rules-str))
+ (if (eq (car-safe rules) 'error)
+ (error "Bad format in expression: %s" (nth 1 rules)))
+ (if (= (length rules) 1)
+ (setq rules (car rules))
+ (setq rules (cons 'vec rules)))
+ (or (memq (car-safe rules) '(vec var calcFunc-assign
+ calcFunc-condition))
+ (let ((rhs (math-read-expr
+ (read-string (concat "Rewrite from: " rules-str
+ " to: ")))))
+ (if (eq (car-safe rhs) 'error)
+ (error "Bad format in expression: %s" (nth 1 rhs)))
+ (setq rules (list 'calcFunc-assign rules rhs))))
+ (or (eq (car-safe rules) 'var)
+ (calc-record rules "rule"))
+ (setq expr (calc-top-n 1)
+ n 1))
+ (if (eq many 0)
+ (setq many '(var inf var-inf))
+ (if many (setq many (prefix-numeric-value many))))
+ (setq expr (calc-normalize (math-rewrite expr rules many)))
+ (let (sel)
+ (setq expr (calc-locate-select-marker expr)))
+ (calc-pop-push-record-list n "rwrt" (list expr)))
+ (calc-handle-whys))
+)
+
+(defun calc-match (pat)
+ (interactive "sPattern: \n")
+ (calc-slow-wrapper
+ (let (n expr)
+ (if (or (null pat) (equal pat "") (equal pat "$"))
+ (setq expr (calc-top-n 2)
+ pat (calc-top-n 1)
+ n 2)
+ (if (interactive-p) (setq calc-previous-alg-entry pat))
+ (setq pat (if (stringp pat) (math-read-expr pat) pat))
+ (if (eq (car-safe pat) 'error)
+ (error "Bad format in expression: %s" (nth 1 pat)))
+ (if (not (eq (car-safe pat) 'var))
+ (calc-record pat "pat"))
+ (setq expr (calc-top-n 1)
+ n 1))
+ (or (math-vectorp expr) (error "Argument must be a vector"))
+ (if (calc-is-inverse)
+ (calc-enter-result n "mtcn" (math-match-patterns pat expr t))
+ (calc-enter-result n "mtch" (math-match-patterns pat expr nil)))))
+)
+
+
+
+(defun math-rewrite (whole-expr rules &optional mmt-many)
+ (let ((crules (math-compile-rewrites rules))
+ (heads (math-rewrite-heads whole-expr))
+ (trace-buffer (get-buffer "*Trace*"))
+ (calc-display-just 'center)
+ (calc-display-origin 39)
+ (calc-line-breaking 78)
+ (calc-line-numbering nil)
+ (calc-show-selections t)
+ (calc-why nil)
+ (mmt-func (function
+ (lambda (x)
+ (let ((result (math-apply-rewrites x (cdr crules)
+ heads crules)))
+ (if result
+ (progn
+ (if trace-buffer
+ (let ((fmt (math-format-stack-value
+ (list result nil nil))))
+ (save-excursion
+ (set-buffer trace-buffer)
+ (insert "\nrewrite to\n" fmt "\n"))))
+ (setq heads (math-rewrite-heads result heads t))))
+ result)))))
+ (if trace-buffer
+ (let ((fmt (math-format-stack-value (list whole-expr nil nil))))
+ (save-excursion
+ (set-buffer trace-buffer)
+ (setq truncate-lines t)
+ (goto-char (point-max))
+ (insert "\n\nBegin rewriting\n" fmt "\n"))))
+ (or mmt-many (setq mmt-many (or (nth 1 (car crules))
+ math-rewrite-default-iters)))
+ (if (equal mmt-many '(var inf var-inf)) (setq mmt-many 1000000))
+ (if (equal mmt-many '(neg (var inf var-inf))) (setq mmt-many -1000000))
+ (math-rewrite-phase (nth 3 (car crules)))
+ (if trace-buffer
+ (let ((fmt (math-format-stack-value (list whole-expr nil nil))))
+ (save-excursion
+ (set-buffer trace-buffer)
+ (insert "\nDone rewriting"
+ (if (= mmt-many 0) " (reached iteration limit)" "")
+ ":\n" fmt "\n"))))
+ whole-expr)
+)
+(setq math-rewrite-default-iters 100)
+
+(defun math-rewrite-phase (sched)
+ (while (and sched (/= mmt-many 0))
+ (if (listp (car sched))
+ (while (let ((save-expr whole-expr))
+ (math-rewrite-phase (car sched))
+ (not (equal whole-expr save-expr))))
+ (if (symbolp (car sched))
+ (progn
+ (setq whole-expr (math-normalize (list (car sched) whole-expr)))
+ (if trace-buffer
+ (let ((fmt (math-format-stack-value
+ (list whole-expr nil nil))))
+ (save-excursion
+ (set-buffer trace-buffer)
+ (insert "\ncall "
+ (substring (symbol-name (car sched)) 9)
+ ":\n" fmt "\n")))))
+ (let ((math-rewrite-phase (car sched)))
+ (if trace-buffer
+ (save-excursion
+ (set-buffer trace-buffer)
+ (insert (format "\n(Phase %d)\n" math-rewrite-phase))))
+ (while (let ((save-expr whole-expr))
+ (setq whole-expr (math-normalize
+ (math-map-tree-rec whole-expr)))
+ (not (equal whole-expr save-expr)))))))
+ (setq sched (cdr sched)))
+)
+
+(defun calcFunc-rewrite (expr rules &optional many)
+ (or (null many) (integerp many)
+ (equal many '(var inf var-inf)) (equal many '(neg (var inf var-inf)))
+ (math-reject-arg many 'fixnump))
+ (condition-case err
+ (math-rewrite expr rules (or many 1))
+ (error (math-reject-arg rules (nth 1 err))))
+)
+
+(defun calcFunc-match (pat vec)
+ (or (math-vectorp vec) (math-reject-arg vec 'vectorp))
+ (condition-case err
+ (math-match-patterns pat vec nil)
+ (error (math-reject-arg pat (nth 1 err))))
+)
+
+(defun calcFunc-matchnot (pat vec)
+ (or (math-vectorp vec) (math-reject-arg vec 'vectorp))
+ (condition-case err
+ (math-match-patterns pat vec t)
+ (error (math-reject-arg pat (nth 1 err))))
+)
+
+(defun math-match-patterns (pat vec &optional not-flag)
+ (let ((newvec nil)
+ (crules (math-compile-patterns pat)))
+ (while (setq vec (cdr vec))
+ (if (eq (not (math-apply-rewrites (car vec) crules))
+ not-flag)
+ (setq newvec (cons (car vec) newvec))))
+ (cons 'vec (nreverse newvec)))
+)
+
+(defun calcFunc-matches (expr pat)
+ (condition-case err
+ (if (math-apply-rewrites expr (math-compile-patterns pat))
+ 1
+ 0)
+ (error (math-reject-arg pat (nth 1 err))))
+)
+
+(defun calcFunc-vmatches (expr pat)
+ (condition-case err
+ (or (math-apply-rewrites expr (math-compile-patterns pat))
+ 0)
+ (error (math-reject-arg pat (nth 1 err))))
+)
+
+
+
+;;; A compiled rule set is an a-list of entries whose cars are functors,
+;;; and whose cdrs are lists of rules. If there are rules with no
+;;; well-defined head functor, they are included on all lists and also
+;;; on an extra list whose car is nil.
+;;;
+;;; The first entry in the a-list is of the form (schedule A B C ...).
+;;;
+;;; Rule list entries take the form (regs prog head phases), where:
+;;;
+;;; regs is a vector of match registers.
+;;;
+;;; prog is a match program (see below).
+;;;
+;;; head is a rare function name appearing in the rule body (but not the
+;;; head of the whole rule), or nil if none.
+;;;
+;;; phases is a list of phase numbers for which the rule is enabled.
+;;;
+;;; A match program is a list of match instructions.
+;;;
+;;; In the following, "part" is a register number that contains the
+;;; subexpression to be operated on.
+;;;
+;;; Register 0 is the whole expression being matched. The others are
+;;; meta-variables in the pattern, temporaries used for matching and
+;;; backtracking, and constant expressions.
+;;;
+;;; (same part reg)
+;;; The selected part must be math-equal to the contents of "reg".
+;;;
+;;; (same-neg part reg)
+;;; The selected part must be math-equal to the negative of "reg".
+;;;
+;;; (copy part reg)
+;;; The selected part is copied into "reg". (Rarely used.)
+;;;
+;;; (copy-neg part reg)
+;;; The negative of the selected part is copied into "reg".
+;;;
+;;; (integer part)
+;;; The selected part must be an integer.
+;;;
+;;; (real part)
+;;; The selected part must be a real.
+;;;
+;;; (constant part)
+;;; The selected part must be a constant.
+;;;
+;;; (negative part)
+;;; The selected part must "look" negative.
+;;;
+;;; (rel part op reg)
+;;; The selected part must satisfy "part op reg", where "op"
+;;; is one of the 6 relational ops, and "reg" is a register.
+;;;
+;;; (mod part modulo value)
+;;; The selected part must satisfy "part % modulo = value", where
+;;; "modulo" and "value" are constants.
+;;;
+;;; (func part head reg1 reg2 ... regn)
+;;; The selected part must be an n-ary call to function "head".
+;;; The arguments are stored in "reg1" through "regn".
+;;;
+;;; (func-def part head defs reg1 reg2 ... regn)
+;;; The selected part must be an n-ary call to function "head".
+;;; "Defs" is a list of value/register number pairs for default args.
+;;; If a match, assign default values to registers and then skip
+;;; immediately over any following "func-def" instructions and
+;;; the following "func" instruction. If wrong number of arguments,
+;;; proceed to the following "func-def" or "func" instruction.
+;;;
+;;; (func-opt part head defs reg1)
+;;; Like func-def with "n=1", except that if the selected part is
+;;; not a call to "head", then the part itself successfully matches
+;;; "reg1" (and the defaults are assigned).
+;;;
+;;; (try part heads mark reg1 [def])
+;;; The selected part must be a function of the correct type which is
+;;; associative and/or commutative. "Heads" is a list of acceptable
+;;; types. An initial assignment of arguments to "reg1" is tried.
+;;; If the program later fails, it backtracks to this instruction
+;;; and tries other assignments of arguments to "reg1".
+;;; If "def" exists and normal matching fails, backtrack and assign
+;;; "part" to "reg1", and "def" to "reg2" in the following "try2".
+;;; The "mark" is a vector of size 5; only "mark[3-4]" are initialized.
+;;; "mark[0]" points to the argument list; "mark[1]" points to the
+;;; current argument; "mark[2]" is 0 if there are two arguments,
+;;; 1 if reg1 is matching single arguments, 2 if reg2 is matching
+;;; single arguments (a+b+c+d is never split as (a+b)+(c+d)), or
+;;; 3 if reg2 is matching "def"; "mark[3]" is 0 if the function must
+;;; have two arguments, 1 if phase-2 can be skipped, 2 if full
+;;; backtracking is necessary; "mark[4]" is t if the arguments have
+;;; been switched from the order given in the original pattern.
+;;;
+;;; (try2 try reg2)
+;;; Every "try" will be followed by a "try2" whose "try" field is
+;;; a pointer to the corresponding "try". The arguments which were
+;;; not stored in "reg1" by that "try" are now stored in "reg2".
+;;;
+;;; (alt instr nil mark)
+;;; Basic backtracking. Execute the instruction sequence "instr".
+;;; If this fails, back up and execute following the "alt" instruction.
+;;; The "mark" must be the vector "[nil nil 4]". The "instr" sequence
+;;; should execute "end-alt" at the end.
+;;;
+;;; (end-alt ptr)
+;;; Register success of the first alternative of a previous "alt".
+;;; "Ptr" is a pointer to the next instruction following that "alt".
+;;;
+;;; (apply part reg1 reg2)
+;;; The selected part must be a function call. The functor
+;;; (as a variable name) is stored in "reg1"; the arguments
+;;; (as a vector) are stored in "reg2".
+;;;
+;;; (cons part reg1 reg2)
+;;; The selected part must be a nonempty vector. The first element
+;;; of the vector is stored in "reg1"; the rest of the vector
+;;; (as another vector) is stored in "reg2".
+;;;
+;;; (rcons part reg1 reg2)
+;;; The selected part must be a nonempty vector. The last element
+;;; of the vector is stored in "reg2"; the rest of the vector
+;;; (as another vector) is stored in "reg1".
+;;;
+;;; (select part reg)
+;;; If the selected part is a unary call to function "select", its
+;;; argument is stored in "reg"; otherwise (provided this is an `a r'
+;;; and not a `g r' command) the selected part is stored in "reg".
+;;;
+;;; (cond expr)
+;;; The "expr", with registers substituted, must simplify to
+;;; a non-zero value.
+;;;
+;;; (let reg expr)
+;;; Evaluate "expr" and store the result in "reg". Always succeeds.
+;;;
+;;; (done rhs remember)
+;;; Rewrite the expression to "rhs", with register substituted.
+;;; Normalize; if the result is different from the original
+;;; expression, the match has succeeded. This is the last
+;;; instruction of every program. If "remember" is non-nil,
+;;; record the result of the match as a new literal rule.
+
+
+;;; Pseudo-functions related to rewrites:
+;;;
+;;; In patterns: quote, plain, condition, opt, apply, cons, select
+;;;
+;;; In righthand sides: quote, plain, eval, evalsimp, evalextsimp,
+;;; apply, cons, select
+;;;
+;;; In conditions: let + same as for righthand sides
+
+;;; Some optimizations that would be nice to have:
+;;;
+;;; * Merge registers with disjoint lifetimes.
+;;; * Merge constant registers with equivalent values.
+;;;
+;;; * If an argument of a commutative op math-depends neither on the
+;;; rest of the pattern nor on any of the conditions, then no backtracking
+;;; should be done for that argument. (This won't apply to very many
+;;; cases.)
+;;;
+;;; * If top functor is "select", and its argument is a unique function,
+;;; add the rule to the lists for both "select" and that function.
+;;; (Currently rules like this go on the "nil" list.)
+;;; Same for "func-opt" functions. (Though not urgent for these.)
+;;;
+;;; * Shouldn't evaluate a "let" condition until the end, or until it
+;;; would enable another condition to be evaluated.
+;;;
+
+;;; Some additional features to add / things to think about:
+;;;
+;;; * Figure out what happens to "a +/- b" and "a +/- opt(b)".
+;;;
+;;; * Same for interval forms.
+;;;
+;;; * Have a name(v,pat) pattern which matches pat, and gives the
+;;; whole match the name v. Beware of circular structures!
+;;;
+
+(defun math-compile-patterns (pats)
+ (if (and (eq (car-safe pats) 'var)
+ (calc-var-value (nth 2 pats)))
+ (let ((prop (get (nth 2 pats) 'math-pattern-cache)))
+ (or prop
+ (put (nth 2 pats) 'math-pattern-cache (setq prop (list nil))))
+ (or (eq (car prop) (symbol-value (nth 2 pats)))
+ (progn
+ (setcdr prop (math-compile-patterns
+ (symbol-value (nth 2 pats))))
+ (setcar prop (symbol-value (nth 2 pats)))))
+ (cdr prop))
+ (let ((math-rewrite-whole t))
+ (cdr (math-compile-rewrites (cons
+ 'vec
+ (mapcar (function (lambda (x)
+ (list 'vec x t)))
+ (if (eq (car-safe pats) 'vec)
+ (cdr pats)
+ (list pats))))))))
+)
+(setq math-rewrite-whole nil)
+(setq math-make-import-list nil)
+
+(defun math-compile-rewrites (rules &optional name)
+ (if (eq (car-safe rules) 'var)
+ (let ((prop (get (nth 2 rules) 'math-rewrite-cache))
+ (math-import-list nil)
+ (math-make-import-list t)
+ p)
+ (or (calc-var-value (nth 2 rules))
+ (error "Rules variable %s has no stored value" (nth 1 rules)))
+ (or prop
+ (put (nth 2 rules) 'math-rewrite-cache
+ (setq prop (list (list (cons (nth 2 rules) nil))))))
+ (setq p (car prop))
+ (while (and p (eq (symbol-value (car (car p))) (cdr (car p))))
+ (setq p (cdr p)))
+ (or (null p)
+ (progn
+ (message "Compiling rule set %s..." (nth 1 rules))
+ (setcdr prop (math-compile-rewrites
+ (symbol-value (nth 2 rules))
+ (nth 2 rules)))
+ (message "Compiling rule set %s...done" (nth 1 rules))
+ (setcar prop (cons (cons (nth 2 rules)
+ (symbol-value (nth 2 rules)))
+ math-import-list))))
+ (cdr prop))
+ (if (or (not (eq (car-safe rules) 'vec))
+ (and (memq (length rules) '(3 4))
+ (let ((p rules))
+ (while (and (setq p (cdr p))
+ (memq (car-safe (car p))
+ '(vec
+ calcFunc-assign
+ calcFunc-condition
+ calcFunc-import
+ calcFunc-phase
+ calcFunc-schedule
+ calcFunc-iterations))))
+ p)))
+ (setq rules (list rules))
+ (setq rules (cdr rules)))
+ (if (assq 'calcFunc-import rules)
+ (let ((pp (setq rules (copy-sequence rules)))
+ p part)
+ (while (setq p (car (cdr pp)))
+ (if (eq (car-safe p) 'calcFunc-import)
+ (progn
+ (setcdr pp (cdr (cdr pp)))
+ (or (and (eq (car-safe (nth 1 p)) 'var)
+ (setq part (calc-var-value (nth 2 (nth 1 p))))
+ (memq (car-safe part) '(vec
+ calcFunc-assign
+ calcFunc-condition)))
+ (error "Argument of import() must be a rules variable"))
+ (if math-make-import-list
+ (setq math-import-list
+ (cons (cons (nth 2 (nth 1 p))
+ (symbol-value (nth 2 (nth 1 p))))
+ math-import-list)))
+ (while (setq p (cdr (cdr p)))
+ (or (cdr p)
+ (error "import() must have odd number of arguments"))
+ (setq part (math-rwcomp-substitute part
+ (car p) (nth 1 p))))
+ (if (eq (car-safe part) 'vec)
+ (setq part (cdr part))
+ (setq part (list part)))
+ (setcdr pp (append part (cdr pp))))
+ (setq pp (cdr pp))))))
+ (let ((rule-set nil)
+ (all-heads nil)
+ (nil-rules nil)
+ (rule-count 0)
+ (math-schedule nil)
+ (math-iterations nil)
+ (math-phases nil)
+ (math-all-phases nil)
+ (math-remembering nil)
+ math-pattern math-rhs math-conds)
+ (while rules
+ (cond
+ ((and (eq (car-safe (car rules)) 'calcFunc-iterations)
+ (= (length (car rules)) 2))
+ (or (integerp (nth 1 (car rules)))
+ (equal (nth 1 (car rules)) '(var inf var-inf))
+ (equal (nth 1 (car rules)) '(neg (var inf var-inf)))
+ (error "Invalid argument for iterations(n)"))
+ (or math-iterations
+ (setq math-iterations (nth 1 (car rules)))))
+ ((eq (car-safe (car rules)) 'calcFunc-schedule)
+ (or math-schedule
+ (setq math-schedule (math-parse-schedule (cdr (car rules))))))
+ ((eq (car-safe (car rules)) 'calcFunc-phase)
+ (setq math-phases (cdr (car rules)))
+ (if (equal math-phases '((var all var-all)))
+ (setq math-phases nil))
+ (let ((p math-phases))
+ (while p
+ (or (integerp (car p))
+ (error "Phase numbers must be small integers"))
+ (or (memq (car p) math-all-phases)
+ (setq math-all-phases (cons (car p) math-all-phases)))
+ (setq p (cdr p)))))
+ ((or (and (eq (car-safe (car rules)) 'vec)
+ (cdr (cdr (car rules)))
+ (not (nthcdr 4 (car rules)))
+ (setq math-conds (nth 3 (car rules))
+ math-rhs (nth 2 (car rules))
+ math-pattern (nth 1 (car rules))))
+ (progn
+ (setq math-conds nil
+ math-pattern (car rules))
+ (while (and (eq (car-safe math-pattern) 'calcFunc-condition)
+ (= (length math-pattern) 3))
+ (let ((cond (nth 2 math-pattern)))
+ (setq math-conds (if math-conds
+ (list 'calcFunc-land math-conds cond)
+ cond)
+ math-pattern (nth 1 math-pattern))))
+ (and (eq (car-safe math-pattern) 'calcFunc-assign)
+ (= (length math-pattern) 3)
+ (setq math-rhs (nth 2 math-pattern)
+ math-pattern (nth 1 math-pattern)))))
+ (let* ((math-prog (list nil))
+ (math-prog-last math-prog)
+ (math-num-regs 1)
+ (math-regs (list (list nil 0 nil nil)))
+ (math-bound-vars nil)
+ (math-aliased-vars nil)
+ (math-copy-neg nil))
+ (setq math-conds (and math-conds (math-flatten-lands math-conds)))
+ (math-rwcomp-pattern math-pattern 0)
+ (while math-conds
+ (let ((expr (car math-conds)))
+ (setq math-conds (cdr math-conds))
+ (math-rwcomp-cond-instr expr)))
+ (math-rwcomp-instr 'done
+ (if (eq math-rhs t)
+ (cons 'vec
+ (delq
+ nil
+ (nreverse
+ (mapcar
+ (function
+ (lambda (v)
+ (and (car v)
+ (list
+ 'calcFunc-assign
+ (math-build-var-name
+ (car v))
+ (math-rwcomp-register-expr
+ (nth 1 v))))))
+ math-regs))))
+ (math-rwcomp-match-vars math-rhs))
+ math-remembering)
+ (setq math-prog (cdr math-prog))
+ (let* ((heads (math-rewrite-heads math-pattern))
+ (rule (list (vconcat
+ (nreverse
+ (mapcar (function (lambda (x) (nth 3 x)))
+ math-regs)))
+ math-prog
+ heads
+ math-phases))
+ (head (and (not (Math-primp math-pattern))
+ (not (and (eq (car (car math-prog)) 'try)
+ (nth 5 (car math-prog))))
+ (not (memq (car (car math-prog)) '(func-opt
+ apply
+ select
+ alt)))
+ (if (memq (car (car math-prog)) '(func
+ func-def))
+ (nth 2 (car math-prog))
+ (if (eq (car math-pattern) 'calcFunc-quote)
+ (car-safe (nth 1 math-pattern))
+ (car math-pattern))))))
+ (let (found)
+ (while heads
+ (if (setq found (assq (car heads) all-heads))
+ (setcdr found (1+ (cdr found)))
+ (setq all-heads (cons (cons (car heads) 1) all-heads)))
+ (setq heads (cdr heads))))
+ (if (eq head '-) (setq head '+))
+ (if (memq head '(calcFunc-cons calcFunc-rcons)) (setq head 'vec))
+ (if head
+ (progn
+ (nconc (or (assq head rule-set)
+ (car (setq rule-set (cons (cons head
+ (copy-sequence
+ nil-rules))
+ rule-set))))
+ (list rule))
+ (if (eq head '*)
+ (nconc (or (assq '/ rule-set)
+ (car (setq rule-set (cons (cons
+ '/
+ (copy-sequence
+ nil-rules))
+ rule-set))))
+ (list rule))))
+ (setq nil-rules (nconc nil-rules (list rule)))
+ (let ((ptr rule-set))
+ (while ptr
+ (nconc (car ptr) (list rule))
+ (setq ptr (cdr ptr))))))))
+ (t
+ (error "Rewrite rule set must be a vector of A := B rules")))
+ (setq rules (cdr rules)))
+ (if nil-rules
+ (setq rule-set (cons (cons nil nil-rules) rule-set)))
+ (setq all-heads (mapcar 'car
+ (sort all-heads (function
+ (lambda (x y)
+ (< (cdr x) (cdr y)))))))
+ (let ((set rule-set)
+ rule heads ptr)
+ (while set
+ (setq rule (cdr (car set)))
+ (while rule
+ (if (consp (setq heads (nth 2 (car rule))))
+ (progn
+ (setq heads (delq (car (car set)) heads)
+ ptr all-heads)
+ (while (and ptr (not (memq (car ptr) heads)))
+ (setq ptr (cdr ptr)))
+ (setcar (nthcdr 2 (car rule)) (car ptr))))
+ (setq rule (cdr rule)))
+ (setq set (cdr set))))
+ (let ((plus (assq '+ rule-set)))
+ (if plus
+ (setq rule-set (cons (cons '- (cdr plus)) rule-set))))
+ (cons (list 'schedule math-iterations name
+ (or math-schedule
+ (sort math-all-phases '<)
+ (list 1)))
+ rule-set)))
+)
+
+(defun math-flatten-lands (expr)
+ (if (eq (car-safe expr) 'calcFunc-land)
+ (append (math-flatten-lands (nth 1 expr))
+ (math-flatten-lands (nth 2 expr)))
+ (list expr))
+)
+
+(defun math-rewrite-heads (expr &optional more all)
+ (let ((heads more)
+ (skips (and (not all)
+ '(calcFunc-apply calcFunc-condition calcFunc-opt
+ calcFunc-por calcFunc-pnot)))
+ (blanks (and (not all)
+ '(calcFunc-quote calcFunc-plain calcFunc-select
+ calcFunc-cons calcFunc-rcons
+ calcFunc-pand))))
+ (or (Math-primp expr)
+ (math-rewrite-heads-rec expr))
+ heads)
+)
+
+(defun math-rewrite-heads-rec (expr)
+ (or (memq (car expr) skips)
+ (progn
+ (or (memq (car expr) heads)
+ (memq (car expr) blanks)
+ (memq 'algebraic (get (car expr) 'math-rewrite-props))
+ (setq heads (cons (car expr) heads)))
+ (while (setq expr (cdr expr))
+ (or (Math-primp (car expr))
+ (math-rewrite-heads-rec (car expr))))))
+)
+
+(defun math-parse-schedule (sched)
+ (mapcar (function
+ (lambda (s)
+ (if (integerp s)
+ s
+ (if (math-vectorp s)
+ (math-parse-schedule (cdr s))
+ (if (eq (car-safe s) 'var)
+ (math-var-to-calcFunc s)
+ (error "Improper component in rewrite schedule"))))))
+ sched)
+)
+
+(defun math-rwcomp-match-vars (expr)
+ (if (Math-primp expr)
+ (if (eq (car-safe expr) 'var)
+ (let ((entry (assq (nth 2 expr) math-regs)))
+ (if entry
+ (math-rwcomp-register-expr (nth 1 entry))
+ expr))
+ expr)
+ (if (and (eq (car expr) 'calcFunc-quote)
+ (= (length expr) 2))
+ (math-rwcomp-match-vars (nth 1 expr))
+ (if (and (eq (car expr) 'calcFunc-plain)
+ (= (length expr) 2)
+ (not (Math-primp (nth 1 expr))))
+ (list (car expr)
+ (cons (car (nth 1 expr))
+ (mapcar 'math-rwcomp-match-vars (cdr (nth 1 expr)))))
+ (cons (car expr)
+ (mapcar 'math-rwcomp-match-vars (cdr expr))))))
+)
+
+(defun math-rwcomp-register-expr (num)
+ (let ((entry (nth (1- (- math-num-regs num)) math-regs)))
+ (if (nth 2 entry)
+ (list 'neg (list 'calcFunc-register (nth 1 entry)))
+ (list 'calcFunc-register (nth 1 entry))))
+)
+
+(defun math-rwcomp-substitute (expr old new)
+ (if (and (eq (car-safe old) 'var)
+ (memq (car-safe new) '(var calcFunc-lambda)))
+ (let ((old-func (math-var-to-calcFunc old))
+ (new-func (math-var-to-calcFunc new)))
+ (math-rwcomp-subst-rec expr))
+ (let ((old-func nil))
+ (math-rwcomp-subst-rec expr)))
+)
+
+(defun math-rwcomp-subst-rec (expr)
+ (cond ((equal expr old) new)
+ ((Math-primp expr) expr)
+ (t (if (eq (car expr) old-func)
+ (math-build-call new-func (mapcar 'math-rwcomp-subst-rec
+ (cdr expr)))
+ (cons (car expr)
+ (mapcar 'math-rwcomp-subst-rec (cdr expr))))))
+)
+
+(setq math-rwcomp-tracing nil)
+
+(defun math-rwcomp-trace (instr)
+ (if math-rwcomp-tracing (progn (terpri) (princ instr)))
+ instr
+)
+
+(defun math-rwcomp-instr (&rest instr)
+ (setcdr math-prog-last
+ (setq math-prog-last (list (math-rwcomp-trace instr))))
+)
+
+(defun math-rwcomp-multi-instr (tail &rest instr)
+ (setcdr math-prog-last
+ (setq math-prog-last (list (math-rwcomp-trace (append instr tail)))))
+)
+
+(defun math-rwcomp-bind-var (reg var)
+ (setcar (math-rwcomp-reg-entry reg) (nth 2 var))
+ (setq math-bound-vars (cons (nth 2 var) math-bound-vars))
+ (math-rwcomp-do-conditions)
+)
+
+(defun math-rwcomp-unbind-vars (mark)
+ (while (not (eq math-bound-vars mark))
+ (setcar (assq (car math-bound-vars) math-regs) nil)
+ (setq math-bound-vars (cdr math-bound-vars)))
+)
+
+(defun math-rwcomp-do-conditions ()
+ (let ((cond math-conds))
+ (while cond
+ (if (math-rwcomp-all-regs-done (car cond))
+ (let ((expr (car cond)))
+ (setq math-conds (delq (car cond) math-conds))
+ (setcar cond 1)
+ (math-rwcomp-cond-instr expr)))
+ (setq cond (cdr cond))))
+)
+
+(defun math-rwcomp-cond-instr (expr)
+ (let (op arg)
+ (cond ((and (eq (car-safe expr) 'calcFunc-matches)
+ (= (length expr) 3)
+ (eq (car-safe (setq arg (math-rwcomp-match-vars (nth 1 expr))))
+ 'calcFunc-register))
+ (math-rwcomp-pattern (nth 2 expr) (nth 1 arg)))
+ ((math-numberp (setq expr (math-rwcomp-match-vars expr)))
+ (if (Math-zerop expr)
+ (math-rwcomp-instr 'backtrack)))
+ ((and (eq (car expr) 'calcFunc-let)
+ (= (length expr) 3))
+ (let ((reg (math-rwcomp-reg)))
+ (math-rwcomp-instr 'let reg (nth 2 expr))
+ (math-rwcomp-pattern (nth 1 expr) reg)))
+ ((and (eq (car expr) 'calcFunc-let)
+ (= (length expr) 2)
+ (eq (car-safe (nth 1 expr)) 'calcFunc-assign)
+ (= (length (nth 1 expr)) 3))
+ (let ((reg (math-rwcomp-reg)))
+ (math-rwcomp-instr 'let reg (nth 2 (nth 1 expr)))
+ (math-rwcomp-pattern (nth 1 (nth 1 expr)) reg)))
+ ((and (setq op (cdr (assq (car-safe expr)
+ '( (calcFunc-integer . integer)
+ (calcFunc-real . real)
+ (calcFunc-constant . constant)
+ (calcFunc-negative . negative) ))))
+ (= (length expr) 2)
+ (or (and (eq (car-safe (nth 1 expr)) 'neg)
+ (memq op '(integer real constant))
+ (setq arg (nth 1 (nth 1 expr))))
+ (setq arg (nth 1 expr)))
+ (eq (car-safe (setq arg (nth 1 expr))) 'calcFunc-register))
+ (math-rwcomp-instr op (nth 1 arg)))
+ ((and (assq (car-safe expr) calc-tweak-eqn-table)
+ (= (length expr) 3)
+ (eq (car-safe (nth 1 expr)) 'calcFunc-register))
+ (if (math-constp (nth 2 expr))
+ (let ((reg (math-rwcomp-reg)))
+ (setcar (nthcdr 3 (car math-regs)) (nth 2 expr))
+ (math-rwcomp-instr 'rel (nth 1 (nth 1 expr))
+ (car expr) reg))
+ (if (eq (car (nth 2 expr)) 'calcFunc-register)
+ (math-rwcomp-instr 'rel (nth 1 (nth 1 expr))
+ (car expr) (nth 1 (nth 2 expr)))
+ (math-rwcomp-instr 'cond expr))))
+ ((and (eq (car-safe expr) 'calcFunc-eq)
+ (= (length expr) 3)
+ (eq (car-safe (nth 1 expr)) '%)
+ (eq (car-safe (nth 1 (nth 1 expr))) 'calcFunc-register)
+ (math-constp (nth 2 (nth 1 expr)))
+ (math-constp (nth 2 expr)))
+ (math-rwcomp-instr 'mod (nth 1 (nth 1 (nth 1 expr)))
+ (nth 2 (nth 1 expr)) (nth 2 expr)))
+ ((equal expr '(var remember var-remember))
+ (setq math-remembering 1))
+ ((and (eq (car-safe expr) 'calcFunc-remember)
+ (= (length expr) 2))
+ (setq math-remembering (if math-remembering
+ (list 'calcFunc-lor
+ math-remembering (nth 1 expr))
+ (nth 1 expr))))
+ (t (math-rwcomp-instr 'cond expr))))
+)
+
+(defun math-rwcomp-same-instr (reg1 reg2 neg)
+ (math-rwcomp-instr (if (eq (eq (nth 2 (math-rwcomp-reg-entry reg1))
+ (nth 2 (math-rwcomp-reg-entry reg2)))
+ neg)
+ 'same-neg
+ 'same)
+ reg1 reg2)
+)
+
+(defun math-rwcomp-copy-instr (reg1 reg2 neg)
+ (if (eq (eq (nth 2 (math-rwcomp-reg-entry reg1))
+ (nth 2 (math-rwcomp-reg-entry reg2)))
+ neg)
+ (math-rwcomp-instr 'copy-neg reg1 reg2)
+ (or (eq reg1 reg2)
+ (math-rwcomp-instr 'copy reg1 reg2)))
+)
+
+(defun math-rwcomp-reg ()
+ (prog1
+ math-num-regs
+ (setq math-regs (cons (list nil math-num-regs nil 0) math-regs)
+ math-num-regs (1+ math-num-regs)))
+)
+
+(defun math-rwcomp-reg-entry (num)
+ (nth (1- (- math-num-regs num)) math-regs)
+)
+
+
+(defun math-rwcomp-pattern (expr part &optional not-direct)
+ (cond ((or (math-rwcomp-no-vars expr)
+ (and (eq (car expr) 'calcFunc-quote)
+ (= (length expr) 2)
+ (setq expr (nth 1 expr))))
+ (if (eq (car-safe expr) 'calcFunc-register)
+ (math-rwcomp-same-instr part (nth 1 expr) nil)
+ (let ((reg (math-rwcomp-reg)))
+ (setcar (nthcdr 3 (car math-regs)) expr)
+ (math-rwcomp-same-instr part reg nil))))
+ ((eq (car expr) 'var)
+ (let ((entry (assq (nth 2 expr) math-regs)))
+ (if entry
+ (math-rwcomp-same-instr part (nth 1 entry) nil)
+ (if not-direct
+ (let ((reg (math-rwcomp-reg)))
+ (math-rwcomp-pattern expr reg)
+ (math-rwcomp-copy-instr part reg nil))
+ (if (setq entry (assq (nth 2 expr) math-aliased-vars))
+ (progn
+ (setcar (math-rwcomp-reg-entry (nth 1 entry))
+ (nth 2 expr))
+ (setcar entry nil)
+ (math-rwcomp-copy-instr part (nth 1 entry) nil))
+ (math-rwcomp-bind-var part expr))))))
+ ((and (eq (car expr) 'calcFunc-select)
+ (= (length expr) 2))
+ (let ((reg (math-rwcomp-reg)))
+ (math-rwcomp-instr 'select part reg)
+ (math-rwcomp-pattern (nth 1 expr) reg)))
+ ((and (eq (car expr) 'calcFunc-opt)
+ (memq (length expr) '(2 3)))
+ (error "opt( ) occurs in context where it is not allowed"))
+ ((eq (car expr) 'neg)
+ (if (eq (car (nth 1 expr)) 'var)
+ (let ((entry (assq (nth 2 (nth 1 expr)) math-regs)))
+ (if entry
+ (math-rwcomp-same-instr part (nth 1 entry) t)
+ (if math-copy-neg
+ (let ((reg (math-rwcomp-best-reg (nth 1 expr))))
+ (math-rwcomp-copy-instr part reg t)
+ (math-rwcomp-pattern (nth 1 expr) reg))
+ (setcar (cdr (cdr (math-rwcomp-reg-entry part))) t)
+ (math-rwcomp-pattern (nth 1 expr) part))))
+ (if (math-rwcomp-is-algebraic (nth 1 expr))
+ (math-rwcomp-cond-instr (list 'calcFunc-eq
+ (math-rwcomp-register-expr part)
+ expr))
+ (let ((reg (math-rwcomp-reg)))
+ (math-rwcomp-instr 'func part 'neg reg)
+ (math-rwcomp-pattern (nth 1 expr) reg)))))
+ ((and (eq (car expr) 'calcFunc-apply)
+ (= (length expr) 3))
+ (let ((reg1 (math-rwcomp-reg))
+ (reg2 (math-rwcomp-reg)))
+ (math-rwcomp-instr 'apply part reg1 reg2)
+ (math-rwcomp-pattern (nth 1 expr) reg1)
+ (math-rwcomp-pattern (nth 2 expr) reg2)))
+ ((and (eq (car expr) 'calcFunc-cons)
+ (= (length expr) 3))
+ (let ((reg1 (math-rwcomp-reg))
+ (reg2 (math-rwcomp-reg)))
+ (math-rwcomp-instr 'cons part reg1 reg2)
+ (math-rwcomp-pattern (nth 1 expr) reg1)
+ (math-rwcomp-pattern (nth 2 expr) reg2)))
+ ((and (eq (car expr) 'calcFunc-rcons)
+ (= (length expr) 3))
+ (let ((reg1 (math-rwcomp-reg))
+ (reg2 (math-rwcomp-reg)))
+ (math-rwcomp-instr 'rcons part reg1 reg2)
+ (math-rwcomp-pattern (nth 1 expr) reg1)
+ (math-rwcomp-pattern (nth 2 expr) reg2)))
+ ((and (eq (car expr) 'calcFunc-condition)
+ (>= (length expr) 3))
+ (math-rwcomp-pattern (nth 1 expr) part)
+ (setq expr (cdr expr))
+ (while (setq expr (cdr expr))
+ (let ((cond (math-flatten-lands (car expr))))
+ (while cond
+ (if (math-rwcomp-all-regs-done (car cond))
+ (math-rwcomp-cond-instr (car cond))
+ (setq math-conds (cons (car cond) math-conds)))
+ (setq cond (cdr cond))))))
+ ((and (eq (car expr) 'calcFunc-pand)
+ (= (length expr) 3))
+ (math-rwcomp-pattern (nth 1 expr) part)
+ (math-rwcomp-pattern (nth 2 expr) part))
+ ((and (eq (car expr) 'calcFunc-por)
+ (= (length expr) 3))
+ (math-rwcomp-instr 'alt nil nil [nil nil 4])
+ (let ((math-conds nil)
+ (head math-prog-last)
+ (mark math-bound-vars)
+ (math-copy-neg t))
+ (math-rwcomp-pattern (nth 1 expr) part t)
+ (let ((amark math-aliased-vars)
+ (math-aliased-vars math-aliased-vars)
+ (tail math-prog-last)
+ (p math-bound-vars)
+ entry)
+ (while (not (eq p mark))
+ (setq entry (assq (car p) math-regs)
+ math-aliased-vars (cons (list (car p) (nth 1 entry) nil)
+ math-aliased-vars)
+ p (cdr p))
+ (setcar (math-rwcomp-reg-entry (nth 1 entry)) nil))
+ (setcar (cdr (car head)) (cdr head))
+ (setcdr head nil)
+ (setq math-prog-last head)
+ (math-rwcomp-pattern (nth 2 expr) part)
+ (math-rwcomp-instr 'same 0 0)
+ (setcdr tail math-prog-last)
+ (setq p math-aliased-vars)
+ (while (not (eq p amark))
+ (if (car (car p))
+ (setcar (math-rwcomp-reg-entry (nth 1 (car p)))
+ (car (car p))))
+ (setq p (cdr p)))))
+ (math-rwcomp-do-conditions))
+ ((and (eq (car expr) 'calcFunc-pnot)
+ (= (length expr) 2))
+ (math-rwcomp-instr 'alt nil nil [nil nil 4])
+ (let ((head math-prog-last)
+ (mark math-bound-vars))
+ (math-rwcomp-pattern (nth 1 expr) part)
+ (math-rwcomp-unbind-vars mark)
+ (math-rwcomp-instr 'end-alt head)
+ (math-rwcomp-instr 'backtrack)
+ (setcar (cdr (car head)) (cdr head))
+ (setcdr head nil)
+ (setq math-prog-last head)))
+ (t (let ((props (get (car expr) 'math-rewrite-props)))
+ (if (and (eq (car expr) 'calcFunc-plain)
+ (= (length expr) 2)
+ (not (math-primp (nth 1 expr))))
+ (setq expr (nth 1 expr))) ; but "props" is still nil
+ (if (and (memq 'algebraic props)
+ (math-rwcomp-is-algebraic expr))
+ (math-rwcomp-cond-instr (list 'calcFunc-eq
+ (math-rwcomp-register-expr part)
+ expr))
+ (if (and (memq 'commut props)
+ (= (length expr) 3))
+ (let ((arg1 (nth 1 expr))
+ (arg2 (nth 2 expr))
+ try1 def code head (flip nil))
+ (if (eq (car expr) '-)
+ (setq arg2 (math-rwcomp-neg arg2)))
+ (setq arg1 (cons arg1 (math-rwcomp-best-reg arg1))
+ arg2 (cons arg2 (math-rwcomp-best-reg arg2)))
+ (or (math-rwcomp-order arg1 arg2)
+ (setq def arg1 arg1 arg2 arg2 def flip t))
+ (if (math-rwcomp-optional-arg (car expr) arg1)
+ (error "Too many opt( ) arguments in this context"))
+ (setq def (math-rwcomp-optional-arg (car expr) arg2)
+ head (if (memq (car expr) '(+ -))
+ '(+ -)
+ (if (eq (car expr) '*)
+ '(* /)
+ (list (car expr))))
+ code (if (math-rwcomp-is-constrained
+ (car arg1) head)
+ (if (math-rwcomp-is-constrained
+ (car arg2) head)
+ 0 1)
+ 2))
+ (math-rwcomp-multi-instr (and def (list def))
+ 'try part head
+ (vector nil nil nil code flip)
+ (cdr arg1))
+ (setq try1 (car math-prog-last))
+ (math-rwcomp-pattern (car arg1) (cdr arg1))
+ (math-rwcomp-instr 'try2 try1 (cdr arg2))
+ (if (and (= part 0) (not def) (not math-rewrite-whole)
+ (not (eq math-rhs t))
+ (setq def (get (car expr)
+ 'math-rewrite-default)))
+ (let ((reg1 (math-rwcomp-reg))
+ (reg2 (math-rwcomp-reg)))
+ (if (= (aref (nth 3 try1) 3) 0)
+ (aset (nth 3 try1) 3 1))
+ (math-rwcomp-instr 'try (cdr arg2)
+ (if (equal head '(* /))
+ '(*) head)
+ (vector nil nil nil
+ (if (= code 0)
+ 1 2)
+ nil)
+ reg1 def)
+ (setq try1 (car math-prog-last))
+ (math-rwcomp-pattern (car arg2) reg1)
+ (math-rwcomp-instr 'try2 try1 reg2)
+ (setq math-rhs (list (if (eq (car expr) '-)
+ '+ (car expr))
+ math-rhs
+ (list 'calcFunc-register
+ reg2))))
+ (math-rwcomp-pattern (car arg2) (cdr arg2))))
+ (let* ((args (mapcar (function
+ (lambda (x)
+ (cons x (math-rwcomp-best-reg x))))
+ (cdr expr)))
+ (args2 (copy-sequence args))
+ (argp (reverse args2))
+ (defs nil)
+ (num 1))
+ (while argp
+ (let ((def (math-rwcomp-optional-arg (car expr)
+ (car argp))))
+ (if def
+ (progn
+ (setq args2 (delq (car argp) args2)
+ defs (cons (cons def (cdr (car argp)))
+ defs))
+ (math-rwcomp-multi-instr
+ (mapcar 'cdr args2)
+ (if (or (and (memq 'unary1 props)
+ (= (length args2) 1)
+ (eq (car args2) (car args)))
+ (and (memq 'unary2 props)
+ (= (length args) 2)
+ (eq (car args2) (nth 1 args))))
+ 'func-opt
+ 'func-def)
+ part (car expr)
+ defs))))
+ (setq argp (cdr argp)))
+ (math-rwcomp-multi-instr (mapcar 'cdr args)
+ 'func part (car expr))
+ (setq args (sort args 'math-rwcomp-order))
+ (while args
+ (math-rwcomp-pattern (car (car args)) (cdr (car args)))
+ (setq num (1+ num)
+ args (cdr args)))))))))
+)
+
+(defun math-rwcomp-best-reg (x)
+ (or (and (eq (car-safe x) 'var)
+ (let ((entry (assq (nth 2 x) math-aliased-vars)))
+ (and entry
+ (not (nth 2 entry))
+ (not (nth 2 (math-rwcomp-reg-entry (nth 1 entry))))
+ (progn
+ (setcar (cdr (cdr entry)) t)
+ (nth 1 entry)))))
+ (math-rwcomp-reg))
+)
+
+(defun math-rwcomp-all-regs-done (expr)
+ (if (Math-primp expr)
+ (or (not (eq (car-safe expr) 'var))
+ (assq (nth 2 expr) math-regs)
+ (eq (nth 2 expr) 'var-remember)
+ (math-const-var expr))
+ (if (and (eq (car expr) 'calcFunc-let)
+ (= (length expr) 3))
+ (math-rwcomp-all-regs-done (nth 2 expr))
+ (if (and (eq (car expr) 'calcFunc-let)
+ (= (length expr) 2)
+ (eq (car-safe (nth 1 expr)) 'calcFunc-assign)
+ (= (length (nth 1 expr)) 3))
+ (math-rwcomp-all-regs-done (nth 2 (nth 1 expr)))
+ (while (and (setq expr (cdr expr))
+ (math-rwcomp-all-regs-done (car expr))))
+ (null expr))))
+)
+
+(defun math-rwcomp-no-vars (expr)
+ (if (Math-primp expr)
+ (or (not (eq (car-safe expr) 'var))
+ (math-const-var expr))
+ (and (not (memq (car expr) '(calcFunc-condition
+ calcFunc-select calcFunc-quote
+ calcFunc-plain calcFunc-opt
+ calcFunc-por calcFunc-pand
+ calcFunc-pnot calcFunc-apply
+ calcFunc-cons calcFunc-rcons)))
+ (progn
+ (while (and (setq expr (cdr expr))
+ (math-rwcomp-no-vars (car expr))))
+ (null expr))))
+)
+
+(defun math-rwcomp-is-algebraic (expr)
+ (if (Math-primp expr)
+ (or (not (eq (car-safe expr) 'var))
+ (math-const-var expr)
+ (assq (nth 2 expr) math-regs))
+ (and (memq 'algebraic (get (car expr) 'math-rewrite-props))
+ (progn
+ (while (and (setq expr (cdr expr))
+ (math-rwcomp-is-algebraic (car expr))))
+ (null expr))))
+)
+
+(defun math-rwcomp-is-constrained (expr not-these)
+ (if (Math-primp expr)
+ (not (eq (car-safe expr) 'var))
+ (if (eq (car expr) 'calcFunc-plain)
+ (math-rwcomp-is-constrained (nth 1 expr) not-these)
+ (not (or (memq (car expr) '(neg calcFunc-select))
+ (memq (car expr) not-these)
+ (and (memq 'commut (get (car expr) 'math-rewrite-props))
+ (or (eq (car-safe (nth 1 expr)) 'calcFunc-opt)
+ (eq (car-safe (nth 2 expr)) 'calcFunc-opt)))))))
+)
+
+(defun math-rwcomp-optional-arg (head argp)
+ (let ((arg (car argp)))
+ (if (eq (car-safe arg) 'calcFunc-opt)
+ (and (memq (length arg) '(2 3))
+ (progn
+ (or (eq (car-safe (nth 1 arg)) 'var)
+ (error "First argument of opt( ) must be a variable"))
+ (setcar argp (nth 1 arg))
+ (if (= (length arg) 2)
+ (or (get head 'math-rewrite-default)
+ (error "opt( ) must include a default in this context"))
+ (nth 2 arg))))
+ (and (eq (car-safe arg) 'neg)
+ (let* ((part (list (nth 1 arg)))
+ (partp (math-rwcomp-optional-arg head part)))
+ (and partp
+ (setcar argp (math-rwcomp-neg (car part)))
+ (math-neg partp))))))
+)
+
+(defun math-rwcomp-neg (expr)
+ (if (memq (car-safe expr) '(* /))
+ (if (eq (car-safe (nth 1 expr)) 'var)
+ (list (car expr) (list 'neg (nth 1 expr)) (nth 2 expr))
+ (if (eq (car-safe (nth 2 expr)) 'var)
+ (list (car expr) (nth 1 expr) (list 'neg (nth 2 expr)))
+ (math-neg expr)))
+ (math-neg expr))
+)
+
+(defun math-rwcomp-assoc-args (expr)
+ (if (and (eq (car-safe (nth 1 expr)) (car expr))
+ (= (length (nth 1 expr)) 3))
+ (math-rwcomp-assoc-args (nth 1 expr))
+ (setq math-args (cons (nth 1 expr) math-args)))
+ (if (and (eq (car-safe (nth 2 expr)) (car expr))
+ (= (length (nth 2 expr)) 3))
+ (math-rwcomp-assoc-args (nth 2 expr))
+ (setq math-args (cons (nth 2 expr) math-args)))
+)
+
+(defun math-rwcomp-addsub-args (expr)
+ (if (memq (car-safe (nth 1 expr)) '(+ -))
+ (math-rwcomp-addsub-args (nth 1 expr))
+ (setq math-args (cons (nth 1 expr) math-args)))
+ (if (eq (car expr) '-)
+ (setq math-args (cons (math-rwcomp-neg (nth 2 expr)) math-args))
+ (if (eq (car-safe (nth 2 expr)) '+)
+ (math-rwcomp-addsub-args (nth 2 expr))
+ (setq math-args (cons (nth 2 expr) math-args))))
+)
+
+(defun math-rwcomp-order (a b)
+ (< (math-rwcomp-priority (car a))
+ (math-rwcomp-priority (car b)))
+)
+
+;;; Order of priority: 0 Constants and other exact matches (first)
+;;; 10 Functions (except below)
+;;; 20 Meta-variables which occur more than once
+;;; 30 Algebraic functions
+;;; 40 Commutative/associative functions
+;;; 50 Meta-variables which occur only once
+;;; +100 for every "!!!" (pnot) in the pattern
+;;; 10000 Optional arguments (last)
+
+(defun math-rwcomp-priority (expr)
+ (+ (math-rwcomp-count-pnots expr)
+ (cond ((eq (car-safe expr) 'calcFunc-opt)
+ 10000)
+ ((math-rwcomp-no-vars expr)
+ 0)
+ ((eq (car expr) 'calcFunc-quote)
+ 0)
+ ((eq (car expr) 'var)
+ (if (assq (nth 2 expr) math-regs)
+ 0
+ (if (= (math-rwcomp-count-refs expr) 1)
+ 50
+ 20)))
+ (t (let ((props (get (car expr) 'math-rewrite-props)))
+ (if (or (memq 'commut props)
+ (memq 'assoc props))
+ 40
+ (if (memq 'algebraic props)
+ 30
+ 10))))))
+)
+
+(defun math-rwcomp-count-refs (var)
+ (let ((count (or (math-expr-contains-count math-pattern var) 0))
+ (p math-conds))
+ (while p
+ (if (eq (car-safe (car p)) 'calcFunc-let)
+ (if (= (length (car p)) 3)
+ (setq count (+ count
+ (or (math-expr-contains-count (nth 2 (car p)) var)
+ 0)))
+ (if (and (= (length (car p)) 2)
+ (eq (car-safe (nth 1 (car p))) 'calcFunc-assign)
+ (= (length (nth 1 (car p))) 3))
+ (setq count (+ count
+ (or (math-expr-contains-count
+ (nth 2 (nth 1 (car p))) var) 0))))))
+ (setq p (cdr p)))
+ count)
+)
+
+(defun math-rwcomp-count-pnots (expr)
+ (if (Math-primp expr)
+ 0
+ (if (eq (car expr) 'calcFunc-pnot)
+ 100
+ (let ((count 0))
+ (while (setq expr (cdr expr))
+ (setq count (+ count (math-rwcomp-count-pnots (car expr)))))
+ count)))
+)
+
+;;; In the current implementation, all associative functions must
+;;; also be commutative.
+
+(put '+ 'math-rewrite-props '(algebraic assoc commut))
+(put '- 'math-rewrite-props '(algebraic assoc commut)) ; see below
+(put '* 'math-rewrite-props '(algebraic assoc commut)) ; see below
+(put '/ 'math-rewrite-props '(algebraic unary1))
+(put '^ 'math-rewrite-props '(algebraic unary1))
+(put '% 'math-rewrite-props '(algebraic))
+(put 'neg 'math-rewrite-props '(algebraic))
+(put 'calcFunc-idiv 'math-rewrite-props '(algebraic))
+(put 'calcFunc-abs 'math-rewrite-props '(algebraic))
+(put 'calcFunc-sign 'math-rewrite-props '(algebraic))
+(put 'calcFunc-round 'math-rewrite-props '(algebraic))
+(put 'calcFunc-rounde 'math-rewrite-props '(algebraic))
+(put 'calcFunc-roundu 'math-rewrite-props '(algebraic))
+(put 'calcFunc-trunc 'math-rewrite-props '(algebraic))
+(put 'calcFunc-floor 'math-rewrite-props '(algebraic))
+(put 'calcFunc-ceil 'math-rewrite-props '(algebraic))
+(put 'calcFunc-re 'math-rewrite-props '(algebraic))
+(put 'calcFunc-im 'math-rewrite-props '(algebraic))
+(put 'calcFunc-conj 'math-rewrite-props '(algebraic))
+(put 'calcFunc-arg 'math-rewrite-props '(algebraic))
+(put 'calcFunc-and 'math-rewrite-props '(assoc commut))
+(put 'calcFunc-or 'math-rewrite-props '(assoc commut))
+(put 'calcFunc-xor 'math-rewrite-props '(assoc commut))
+(put 'calcFunc-eq 'math-rewrite-props '(commut))
+(put 'calcFunc-neq 'math-rewrite-props '(commut))
+(put 'calcFunc-land 'math-rewrite-props '(assoc commut))
+(put 'calcFunc-lor 'math-rewrite-props '(assoc commut))
+(put 'calcFunc-beta 'math-rewrite-props '(commut))
+(put 'calcFunc-gcd 'math-rewrite-props '(assoc commut))
+(put 'calcFunc-lcm 'math-rewrite-props '(assoc commut))
+(put 'calcFunc-max 'math-rewrite-props '(algebraic assoc commut))
+(put 'calcFunc-min 'math-rewrite-props '(algebraic assoc commut))
+(put 'calcFunc-vunion 'math-rewrite-props '(assoc commut))
+(put 'calcFunc-vint 'math-rewrite-props '(assoc commut))
+(put 'calcFunc-vxor 'math-rewrite-props '(assoc commut))
+
+;;; Note: "*" is not commutative for matrix args, but we pretend it is.
+;;; Also, "-" is not commutative but the code tweaks things so that it is.
+
+(put '+ 'math-rewrite-default 0)
+(put '- 'math-rewrite-default 0)
+(put '* 'math-rewrite-default 1)
+(put '/ 'math-rewrite-default 1)
+(put '^ 'math-rewrite-default 1)
+(put 'calcFunc-land 'math-rewrite-default 1)
+(put 'calcFunc-lor 'math-rewrite-default 0)
+(put 'calcFunc-vunion 'math-rewrite-default '(vec))
+(put 'calcFunc-vint 'math-rewrite-default '(vec))
+(put 'calcFunc-vdiff 'math-rewrite-default '(vec))
+(put 'calcFunc-vxor 'math-rewrite-default '(vec))
+
+(defmacro math-rwfail (&optional back)
+ (list 'setq 'pc
+ (list 'and
+ (if back
+ '(setq btrack (cdr btrack))
+ 'btrack)
+ ''((backtrack))))
+)
+
+;;; This monstrosity is necessary because the use of static vectors of
+;;; registers makes rewrite rules non-reentrant. Yucko!
+(defmacro math-rweval (form)
+ (list 'let '((orig (car rules)))
+ '(setcar rules (quote (nil nil nil no-phase)))
+ (list 'unwind-protect
+ form
+ '(setcar rules orig)))
+)
+
+(setq math-rewrite-phase 1)
+
+(defun math-apply-rewrites (expr rules &optional heads ruleset)
+ (and
+ (setq rules (cdr (or (assq (car-safe expr) rules)
+ (assq nil rules))))
+ (let ((result nil)
+ op regs inst part pc mark btrack
+ (tracing math-rwcomp-tracing)
+ (phase math-rewrite-phase))
+ (while rules
+ (or
+ (and (setq part (nth 2 (car rules)))
+ heads
+ (not (memq part heads)))
+ (and (setq part (nth 3 (car rules)))
+ (not (memq phase part)))
+ (progn
+ (setq regs (car (car rules))
+ pc (nth 1 (car rules))
+ btrack nil)
+ (aset regs 0 expr)
+ (while pc
+
+ (and tracing
+ (progn (terpri) (princ (car pc))
+ (if (and (natnump (nth 1 (car pc)))
+ (< (nth 1 (car pc)) (length regs)))
+ (princ (format "\n part = %s"
+ (aref regs (nth 1 (car pc))))))))
+
+ (cond ((eq (setq op (car (setq inst (car pc)))) 'func)
+ (if (and (consp (setq part (aref regs (car (cdr inst)))))
+ (eq (car part)
+ (car (setq inst (cdr (cdr inst)))))
+ (progn
+ (while (and (setq inst (cdr inst)
+ part (cdr part))
+ inst)
+ (aset regs (car inst) (car part)))
+ (not (or inst part))))
+ (setq pc (cdr pc))
+ (math-rwfail)))
+
+ ((eq op 'same)
+ (if (or (equal (setq part (aref regs (nth 1 inst)))
+ (setq mark (aref regs (nth 2 inst))))
+ (Math-equal part mark))
+ (setq pc (cdr pc))
+ (math-rwfail)))
+
+ ((and (eq op 'try)
+ calc-matrix-mode
+ (not (eq calc-matrix-mode 'scalar))
+ (eq (car (nth 2 inst)) '*)
+ (consp (setq part (aref regs (car (cdr inst)))))
+ (eq (car part) '*)
+ (not (math-known-scalarp part)))
+ (setq mark (nth 3 inst)
+ pc (cdr pc))
+ (if (aref mark 4)
+ (progn
+ (aset regs (nth 4 inst) (nth 2 part))
+ (aset mark 1 (cdr (cdr part))))
+ (aset regs (nth 4 inst) (nth 1 part))
+ (aset mark 1 (cdr part)))
+ (aset mark 0 (cdr part))
+ (aset mark 2 0))
+
+ ((eq op 'try)
+ (if (and (consp (setq part (aref regs (car (cdr inst)))))
+ (memq (car part) (nth 2 inst))
+ (= (length part) 3)
+ (or (not (eq (car part) '/))
+ (Math-objectp (nth 2 part))))
+ (progn
+ (setq op nil
+ mark (car (cdr (setq inst (cdr (cdr inst))))))
+ (and
+ (memq 'assoc (get (car part) 'math-rewrite-props))
+ (not (= (aref mark 3) 0))
+ (while (if (and (consp (nth 1 part))
+ (memq (car (nth 1 part)) (car inst)))
+ (setq op (cons (if (eq (car part) '-)
+ (math-rwapply-neg
+ (nth 2 part))
+ (nth 2 part))
+ op)
+ part (nth 1 part))
+ (if (and (consp (nth 2 part))
+ (memq (car (nth 2 part))
+ (car inst))
+ (not (eq (car (nth 2 part)) '-)))
+ (setq op (cons (nth 1 part) op)
+ part (nth 2 part))))))
+ (setq op (cons (nth 1 part)
+ (cons (if (eq (car part) '-)
+ (math-rwapply-neg
+ (nth 2 part))
+ (if (eq (car part) '/)
+ (math-rwapply-inv
+ (nth 2 part))
+ (nth 2 part)))
+ op))
+ btrack (cons pc btrack)
+ pc (cdr pc))
+ (aset regs (nth 2 inst) (car op))
+ (aset mark 0 op)
+ (aset mark 1 op)
+ (aset mark 2 (if (cdr (cdr op)) 1 0)))
+ (if (nth 5 inst)
+ (if (and (consp part)
+ (eq (car part) 'neg)
+ (eq (car (nth 2 inst)) '*)
+ (eq (nth 5 inst) 1))
+ (progn
+ (setq mark (nth 3 inst)
+ pc (cdr pc))
+ (aset regs (nth 4 inst) (nth 1 part))
+ (aset mark 1 -1)
+ (aset mark 2 4))
+ (setq mark (nth 3 inst)
+ pc (cdr pc))
+ (aset regs (nth 4 inst) part)
+ (aset mark 2 3))
+ (math-rwfail))))
+
+ ((eq op 'try2)
+ (setq part (nth 1 inst) ; try instr
+ mark (nth 3 part)
+ op (aref mark 2)
+ pc (cdr pc))
+ (aset regs (nth 2 inst)
+ (cond
+ ((eq op 0)
+ (if (eq (aref mark 0) (aref mark 1))
+ (nth 1 (aref mark 0))
+ (car (aref mark 0))))
+ ((eq op 1)
+ (setq mark (delq (car (aref mark 1))
+ (copy-sequence (aref mark 0)))
+ op (car (nth 2 part)))
+ (if (eq op '*)
+ (progn
+ (setq mark (nreverse mark)
+ part (list '* (nth 1 mark) (car mark))
+ mark (cdr mark))
+ (while (setq mark (cdr mark))
+ (setq part (list '* (car mark) part))))
+ (setq part (car mark)
+ mark (cdr mark)
+ part (if (and (eq op '+)
+ (consp (car mark))
+ (eq (car (car mark)) 'neg))
+ (list '- part
+ (nth 1 (car mark)))
+ (list op part (car mark))))
+ (while (setq mark (cdr mark))
+ (setq part (if (and (eq op '+)
+ (consp (car mark))
+ (eq (car (car mark)) 'neg))
+ (list '- part
+ (nth 1 (car mark)))
+ (list op part (car mark))))))
+ part)
+ ((eq op 2)
+ (car (aref mark 1)))
+ ((eq op 3) (nth 5 part))
+ (t (aref mark 1)))))
+
+ ((eq op 'select)
+ (setq pc (cdr pc))
+ (if (and (consp (setq part (aref regs (nth 1 inst))))
+ (eq (car part) 'calcFunc-select))
+ (aset regs (nth 2 inst) (nth 1 part))
+ (if math-rewrite-selections
+ (math-rwfail)
+ (aset regs (nth 2 inst) part))))
+
+ ((eq op 'same-neg)
+ (if (or (equal (setq part (aref regs (nth 1 inst)))
+ (setq mark (math-neg
+ (aref regs (nth 2 inst)))))
+ (Math-equal part mark))
+ (setq pc (cdr pc))
+ (math-rwfail)))
+
+ ((eq op 'backtrack)
+ (setq inst (car (car btrack)) ; "try" or "alt" instr
+ pc (cdr (car btrack))
+ mark (or (nth 3 inst) [nil nil 4])
+ op (aref mark 2))
+ (cond ((eq op 0)
+ (if (setq op (cdr (aref mark 1)))
+ (aset regs (nth 4 inst) (car (aset mark 1 op)))
+ (if (nth 5 inst)
+ (progn
+ (aset mark 2 3)
+ (aset regs (nth 4 inst)
+ (aref regs (nth 1 inst))))
+ (math-rwfail t))))
+ ((eq op 1)
+ (if (setq op (cdr (aref mark 1)))
+ (aset regs (nth 4 inst) (car (aset mark 1 op)))
+ (if (= (aref mark 3) 1)
+ (if (nth 5 inst)
+ (progn
+ (aset mark 2 3)
+ (aset regs (nth 4 inst)
+ (aref regs (nth 1 inst))))
+ (math-rwfail t))
+ (aset mark 2 2)
+ (aset mark 1 (cons nil (aref mark 0)))
+ (math-rwfail))))
+ ((eq op 2)
+ (if (setq op (cdr (aref mark 1)))
+ (progn
+ (setq mark (delq (car (aset mark 1 op))
+ (copy-sequence
+ (aref mark 0)))
+ op (car (nth 2 inst)))
+ (if (eq op '*)
+ (progn
+ (setq mark (nreverse mark)
+ part (list '* (nth 1 mark)
+ (car mark))
+ mark (cdr mark))
+ (while (setq mark (cdr mark))
+ (setq part (list '* (car mark)
+ part))))
+ (setq part (car mark)
+ mark (cdr mark)
+ part (if (and (eq op '+)
+ (consp (car mark))
+ (eq (car (car mark))
+ 'neg))
+ (list '- part
+ (nth 1 (car mark)))
+ (list op part (car mark))))
+ (while (setq mark (cdr mark))
+ (setq part (if (and (eq op '+)
+ (consp (car mark))
+ (eq (car (car mark))
+ 'neg))
+ (list '- part
+ (nth 1 (car mark)))
+ (list op part (car mark))))))
+ (aset regs (nth 4 inst) part))
+ (if (nth 5 inst)
+ (progn
+ (aset mark 2 3)
+ (aset regs (nth 4 inst)
+ (aref regs (nth 1 inst))))
+ (math-rwfail t))))
+ ((eq op 4)
+ (setq btrack (cdr btrack)))
+ (t (math-rwfail t))))
+
+ ((eq op 'integer)
+ (if (Math-integerp (setq part (aref regs (nth 1 inst))))
+ (setq pc (cdr pc))
+ (if (Math-primp part)
+ (math-rwfail)
+ (setq part (math-rweval (math-simplify part)))
+ (if (Math-integerp part)
+ (setq pc (cdr pc))
+ (math-rwfail)))))
+
+ ((eq op 'real)
+ (if (Math-realp (setq part (aref regs (nth 1 inst))))
+ (setq pc (cdr pc))
+ (if (Math-primp part)
+ (math-rwfail)
+ (setq part (math-rweval (math-simplify part)))
+ (if (Math-realp part)
+ (setq pc (cdr pc))
+ (math-rwfail)))))
+
+ ((eq op 'constant)
+ (if (math-constp (setq part (aref regs (nth 1 inst))))
+ (setq pc (cdr pc))
+ (if (Math-primp part)
+ (math-rwfail)
+ (setq part (math-rweval (math-simplify part)))
+ (if (math-constp part)
+ (setq pc (cdr pc))
+ (math-rwfail)))))
+
+ ((eq op 'negative)
+ (if (math-looks-negp (setq part (aref regs (nth 1 inst))))
+ (setq pc (cdr pc))
+ (if (Math-primp part)
+ (math-rwfail)
+ (setq part (math-rweval (math-simplify part)))
+ (if (math-looks-negp part)
+ (setq pc (cdr pc))
+ (math-rwfail)))))
+
+ ((eq op 'rel)
+ (setq part (math-compare (aref regs (nth 1 inst))
+ (aref regs (nth 3 inst)))
+ op (nth 2 inst))
+ (if (= part 2)
+ (setq part (math-rweval
+ (math-simplify
+ (calcFunc-sign
+ (math-sub (aref regs (nth 1 inst))
+ (aref regs (nth 3 inst))))))))
+ (if (cond ((eq op 'calcFunc-eq)
+ (eq part 0))
+ ((eq op 'calcFunc-neq)
+ (memq part '(-1 1)))
+ ((eq op 'calcFunc-lt)
+ (eq part -1))
+ ((eq op 'calcFunc-leq)
+ (memq part '(-1 0)))
+ ((eq op 'calcFunc-gt)
+ (eq part 1))
+ ((eq op 'calcFunc-geq)
+ (memq part '(0 1))))
+ (setq pc (cdr pc))
+ (math-rwfail)))
+
+ ((eq op 'func-def)
+ (if (and (consp (setq part (aref regs (car (cdr inst)))))
+ (eq (car part)
+ (car (setq inst (cdr (cdr inst))))))
+ (progn
+ (setq inst (cdr inst)
+ mark (car inst))
+ (while (and (setq inst (cdr inst)
+ part (cdr part))
+ inst)
+ (aset regs (car inst) (car part)))
+ (if (or inst part)
+ (setq pc (cdr pc))
+ (while (eq (car (car (setq pc (cdr pc))))
+ 'func-def))
+ (setq pc (cdr pc)) ; skip over "func"
+ (while mark
+ (aset regs (cdr (car mark)) (car (car mark)))
+ (setq mark (cdr mark)))))
+ (math-rwfail)))
+
+ ((eq op 'func-opt)
+ (if (or (not (and (consp
+ (setq part (aref regs (car (cdr inst)))))
+ (eq (car part) (nth 2 inst))))
+ (and (= (length part) 2)
+ (setq part (nth 1 part))))
+ (progn
+ (setq mark (nth 3 inst))
+ (aset regs (nth 4 inst) part)
+ (while (eq (car (car (setq pc (cdr pc)))) 'func-def))
+ (setq pc (cdr pc)) ; skip over "func"
+ (while mark
+ (aset regs (cdr (car mark)) (car (car mark)))
+ (setq mark (cdr mark))))
+ (setq pc (cdr pc))))
+
+ ((eq op 'mod)
+ (if (if (Math-zerop (setq part (aref regs (nth 1 inst))))
+ (Math-zerop (nth 3 inst))
+ (and (not (Math-zerop (nth 2 inst)))
+ (progn
+ (setq part (math-mod part (nth 2 inst)))
+ (or (Math-numberp part)
+ (setq part (math-rweval
+ (math-simplify part))))
+ (Math-equal part (nth 3 inst)))))
+ (setq pc (cdr pc))
+ (math-rwfail)))
+
+ ((eq op 'apply)
+ (if (and (consp (setq part (aref regs (car (cdr inst)))))
+ (not (Math-objvecp part))
+ (not (eq (car part) 'var)))
+ (progn
+ (aset regs (nth 2 inst)
+ (math-calcFunc-to-var (car part)))
+ (aset regs (nth 3 inst)
+ (cons 'vec (cdr part)))
+ (setq pc (cdr pc)))
+ (math-rwfail)))
+
+ ((eq op 'cons)
+ (if (and (consp (setq part (aref regs (car (cdr inst)))))
+ (eq (car part) 'vec)
+ (cdr part))
+ (progn
+ (aset regs (nth 2 inst) (nth 1 part))
+ (aset regs (nth 3 inst) (cons 'vec (cdr (cdr part))))
+ (setq pc (cdr pc)))
+ (math-rwfail)))
+
+ ((eq op 'rcons)
+ (if (and (consp (setq part (aref regs (car (cdr inst)))))
+ (eq (car part) 'vec)
+ (cdr part))
+ (progn
+ (aset regs (nth 2 inst) (calcFunc-rhead part))
+ (aset regs (nth 3 inst) (calcFunc-rtail part))
+ (setq pc (cdr pc)))
+ (math-rwfail)))
+
+ ((eq op 'cond)
+ (if (math-is-true
+ (math-rweval
+ (math-simplify
+ (math-rwapply-replace-regs (nth 1 inst)))))
+ (setq pc (cdr pc))
+ (math-rwfail)))
+
+ ((eq op 'let)
+ (aset regs (nth 1 inst)
+ (math-rweval
+ (math-normalize
+ (math-rwapply-replace-regs (nth 2 inst)))))
+ (setq pc (cdr pc)))
+
+ ((eq op 'copy)
+ (aset regs (nth 2 inst) (aref regs (nth 1 inst)))
+ (setq pc (cdr pc)))
+
+ ((eq op 'copy-neg)
+ (aset regs (nth 2 inst)
+ (math-rwapply-neg (aref regs (nth 1 inst))))
+ (setq pc (cdr pc)))
+
+ ((eq op 'alt)
+ (setq btrack (cons pc btrack)
+ pc (nth 1 inst)))
+
+ ((eq op 'end-alt)
+ (while (and btrack (not (eq (car btrack) (nth 1 inst))))
+ (setq btrack (cdr btrack)))
+ (setq btrack (cdr btrack)
+ pc (cdr pc)))
+
+ ((eq op 'done)
+ (setq result (math-rwapply-replace-regs (nth 1 inst)))
+ (if (or (and (eq (car-safe result) '+)
+ (eq (nth 2 result) 0))
+ (and (eq (car-safe result) '*)
+ (eq (nth 2 result) 1)))
+ (setq result (nth 1 result)))
+ (setq part (and (nth 2 inst)
+ (math-is-true
+ (math-rweval
+ (math-simplify
+ (math-rwapply-replace-regs
+ (nth 2 inst)))))))
+ (if (or (equal result expr)
+ (equal (setq result (math-normalize result)) expr))
+ (setq result nil)
+ (if part (math-rwapply-remember expr result))
+ (setq rules nil))
+ (setq pc nil))
+
+ (t (error "%s is not a valid rewrite opcode" op))))))
+ (setq rules (cdr rules)))
+ result))
+)
+
+(defun math-rwapply-neg (expr)
+ (if (and (consp expr)
+ (memq (car expr) '(* /)))
+ (if (Math-objectp (nth 2 expr))
+ (list (car expr) (nth 1 expr) (math-neg (nth 2 expr)))
+ (list (car expr)
+ (if (Math-objectp (nth 1 expr))
+ (math-neg (nth 1 expr))
+ (list '* -1 (nth 1 expr)))
+ (nth 2 expr)))
+ (math-neg expr))
+)
+
+(defun math-rwapply-inv (expr)
+ (if (and (Math-integerp expr)
+ calc-prefer-frac)
+ (math-make-frac 1 expr)
+ (list '/ 1 expr))
+)
+
+(defun math-rwapply-replace-regs (expr)
+ (cond ((Math-primp expr)
+ expr)
+ ((eq (car expr) 'calcFunc-register)
+ (setq expr (aref regs (nth 1 expr)))
+ (if (eq (car-safe expr) '*)
+ (if (eq (nth 1 expr) -1)
+ (math-neg (nth 2 expr))
+ (if (eq (nth 1 expr) 1)
+ (nth 2 expr)
+ expr))
+ expr))
+ ((and (eq (car expr) 'calcFunc-eval)
+ (= (length expr) 2))
+ (calc-with-default-simplification
+ (math-normalize (math-rwapply-replace-regs (nth 1 expr)))))
+ ((and (eq (car expr) 'calcFunc-evalsimp)
+ (= (length expr) 2))
+ (math-simplify (math-rwapply-replace-regs (nth 1 expr))))
+ ((and (eq (car expr) 'calcFunc-evalextsimp)
+ (= (length expr) 2))
+ (math-simplify-extended (math-rwapply-replace-regs (nth 1 expr))))
+ ((and (eq (car expr) 'calcFunc-apply)
+ (= (length expr) 3))
+ (let ((func (math-rwapply-replace-regs (nth 1 expr)))
+ (args (math-rwapply-replace-regs (nth 2 expr)))
+ call)
+ (if (and (math-vectorp args)
+ (not (eq (car-safe (setq call (math-build-call
+ (math-var-to-calcFunc func)
+ (cdr args))))
+ 'calcFunc-call)))
+ call
+ (list 'calcFunc-apply func args))))
+ ((and (eq (car expr) 'calcFunc-cons)
+ (= (length expr) 3))
+ (let ((head (math-rwapply-replace-regs (nth 1 expr)))
+ (tail (math-rwapply-replace-regs (nth 2 expr))))
+ (if (math-vectorp tail)
+ (cons 'vec (cons head (cdr tail)))
+ (list 'calcFunc-cons head tail))))
+ ((and (eq (car expr) 'calcFunc-rcons)
+ (= (length expr) 3))
+ (let ((head (math-rwapply-replace-regs (nth 1 expr)))
+ (tail (math-rwapply-replace-regs (nth 2 expr))))
+ (if (math-vectorp head)
+ (append head (list tail))
+ (list 'calcFunc-rcons head tail))))
+ ((and (eq (car expr) 'neg)
+ (math-rwapply-reg-looks-negp (nth 1 expr)))
+ (math-rwapply-reg-neg (nth 1 expr)))
+ ((and (eq (car expr) 'neg)
+ (eq (car-safe (nth 1 expr)) 'calcFunc-register)
+ (math-scalarp (aref regs (nth 1 (nth 1 expr)))))
+ (math-neg (math-rwapply-replace-regs (nth 1 expr))))
+ ((and (eq (car expr) '+)
+ (math-rwapply-reg-looks-negp (nth 1 expr)))
+ (list '- (math-rwapply-replace-regs (nth 2 expr))
+ (math-rwapply-reg-neg (nth 1 expr))))
+ ((and (eq (car expr) '+)
+ (math-rwapply-reg-looks-negp (nth 2 expr)))
+ (list '- (math-rwapply-replace-regs (nth 1 expr))
+ (math-rwapply-reg-neg (nth 2 expr))))
+ ((and (eq (car expr) '-)
+ (math-rwapply-reg-looks-negp (nth 2 expr)))
+ (list '+ (math-rwapply-replace-regs (nth 1 expr))
+ (math-rwapply-reg-neg (nth 2 expr))))
+ ((eq (car expr) '*)
+ (cond ((eq (nth 1 expr) -1)
+ (if (math-rwapply-reg-looks-negp (nth 2 expr))
+ (math-rwapply-reg-neg (nth 2 expr))
+ (math-neg (math-rwapply-replace-regs (nth 2 expr)))))
+ ((eq (nth 1 expr) 1)
+ (math-rwapply-replace-regs (nth 2 expr)))
+ ((eq (nth 2 expr) -1)
+ (if (math-rwapply-reg-looks-negp (nth 1 expr))
+ (math-rwapply-reg-neg (nth 1 expr))
+ (math-neg (math-rwapply-replace-regs (nth 1 expr)))))
+ ((eq (nth 2 expr) 1)
+ (math-rwapply-replace-regs (nth 1 expr)))
+ (t
+ (let ((arg1 (math-rwapply-replace-regs (nth 1 expr)))
+ (arg2 (math-rwapply-replace-regs (nth 2 expr))))
+ (cond ((and (eq (car-safe arg1) '/)
+ (eq (nth 1 arg1) 1))
+ (list '/ arg2 (nth 2 arg1)))
+ ((and (eq (car-safe arg2) '/)
+ (eq (nth 1 arg2) 1))
+ (list '/ arg1 (nth 2 arg2)))
+ (t (list '* arg1 arg2)))))))
+ ((eq (car expr) '/)
+ (let ((arg1 (math-rwapply-replace-regs (nth 1 expr)))
+ (arg2 (math-rwapply-replace-regs (nth 2 expr))))
+ (if (eq (car-safe arg2) '/)
+ (list '/ (list '* arg1 (nth 2 arg2)) (nth 1 arg2))
+ (list '/ arg1 arg2))))
+ ((and (eq (car expr) 'calcFunc-plain)
+ (= (length expr) 2))
+ (if (Math-primp (nth 1 expr))
+ (nth 1 expr)
+ (if (eq (car (nth 1 expr)) 'calcFunc-register)
+ (aref regs (nth 1 (nth 1 expr)))
+ (cons (car (nth 1 expr)) (mapcar 'math-rwapply-replace-regs
+ (cdr (nth 1 expr)))))))
+ (t (cons (car expr) (mapcar 'math-rwapply-replace-regs (cdr expr)))))
+)
+
+(defun math-rwapply-reg-looks-negp (expr)
+ (if (eq (car-safe expr) 'calcFunc-register)
+ (math-looks-negp (aref regs (nth 1 expr)))
+ (if (memq (car-safe expr) '(* /))
+ (or (math-rwapply-reg-looks-negp (nth 1 expr))
+ (math-rwapply-reg-looks-negp (nth 2 expr)))))
+)
+
+(defun math-rwapply-reg-neg (expr) ; expr must satisfy rwapply-reg-looks-negp
+ (if (eq (car expr) 'calcFunc-register)
+ (math-neg (math-rwapply-replace-regs expr))
+ (if (math-rwapply-reg-looks-negp (nth 1 expr))
+ (math-rwapply-replace-regs (list (car expr)
+ (math-rwapply-reg-neg (nth 1 expr))
+ (nth 2 expr)))
+ (math-rwapply-replace-regs (list (car expr)
+ (nth 1 expr)
+ (math-rwapply-reg-neg (nth 2 expr))))))
+)
+
+(defun math-rwapply-remember (old new)
+ (let ((varval (symbol-value (nth 2 (car ruleset))))
+ (rules (assq (car-safe old) ruleset)))
+ (if (and (eq (car-safe varval) 'vec)
+ (not (memq (car-safe old) '(nil schedule + -)))
+ rules)
+ (progn
+ (setcdr varval (cons (list 'calcFunc-assign
+ (if (math-rwcomp-no-vars old)
+ old
+ (list 'calcFunc-quote old))
+ new)
+ (cdr varval)))
+ (setcdr rules (cons (list (vector nil old)
+ (list (list 'same 0 1)
+ (list 'done new nil))
+ nil nil)
+ (cdr rules))))))
+)
+
+
+
+