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