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