root/trunk/lisp/calc/calc-rewr.el

Revision 4220, 72.8 kB (checked in by miyoshi, 9 months ago)

Sync up with Emacs22.2.

Line 
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, or (at your option)
14 ;; 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; see the file COPYING.  If not, write to the
23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
25
26 ;;; Commentary:
27
28 ;;; Code:
29
30 ;; This file is autoloaded from calc-ext.el.
31
32 (require 'calc-ext)
33 (require 'calc-macs)
34
35 (defvar math-rewrite-default-iters 100)
36
37 ;; The variable calc-rewr-sel is local to calc-rewrite-selection and
38 ;; calc-rewrite, but is used by calc-locate-selection-marker.
39 (defvar calc-rewr-sel)
40
41 (defun calc-rewrite-selection (rules-str &optional many prefix)
42   (interactive "sRewrite rule(s): \np")
43   (calc-slow-wrapper
44    (calc-preserve-point)
45    (let* ((num (max 1 (calc-locate-cursor-element (point))))
46           (reselect t)
47           (pop-rules nil)
48           rules
49           (entry (calc-top num 'entry))
50           (expr (car entry))
51           (calc-rewr-sel (calc-auto-selection entry))
52           (math-rewrite-selections t)
53           (math-rewrite-default-iters 1))
54      (if (or (null rules-str) (equal rules-str "") (equal rules-str "$"))
55          (if (= num 1)
56              (error "Can't use same stack entry for formula and rules")
57            (setq rules (calc-top-n 1 t)
58                  pop-rules t))
59        (setq rules (if (stringp rules-str)
60                        (math-read-exprs rules-str) rules-str))
61        (if (eq (car-safe rules) 'error)
62            (error "Bad format in expression: %s" (nth 1 rules)))
63        (if (= (length rules) 1)
64            (setq rules (car rules))
65          (setq rules (cons 'vec rules)))
66        (or (memq (car-safe rules) '(vec var calcFunc-assign
67                                         calcFunc-condition))
68            (let ((rhs (math-read-expr
69                        (read-string (concat "Rewrite from:    " rules-str
70                                             "  to: ")))))
71              (if (eq (car-safe rhs) 'error)
72                  (error "Bad format in expression: %s" (nth 1 rhs)))
73              (setq rules (list 'calcFunc-assign rules rhs))))
74        (or (eq (car-safe rules) 'var)
75            (calc-record rules "rule")))
76      (if (eq many 0)
77          (setq many '(var inf var-inf))
78        (if many (setq many (prefix-numeric-value many))))
79      (if calc-rewr-sel
80          (setq expr (calc-replace-sub-formula (car entry)
81                                               calc-rewr-sel
82                                               (list 'calcFunc-select calc-rewr-sel)))
83        (setq expr (car entry)
84              reselect nil
85              math-rewrite-selections nil))
86      (setq expr (calc-encase-atoms
87                  (calc-normalize
88                   (math-rewrite
89                    (calc-normalize expr)
90                    rules many)))
91            calc-rewr-sel nil
92            expr (calc-locate-select-marker expr))
93      (or (consp calc-rewr-sel) (setq calc-rewr-sel nil))
94      (if pop-rules (calc-pop-stack 1))
95      (calc-pop-push-record-list 1 (or prefix "rwrt") (list expr)
96                                 (- num (if pop-rules 1 0))
97                                 (list (and reselect calc-rewr-sel))))
98    (calc-handle-whys)))
99
100 (defun calc-locate-select-marker (expr)
101   (if (Math-primp expr)
102       expr
103     (if (and (eq (car expr) 'calcFunc-select)
104              (= (length expr) 2))
105         (progn
106           (setq calc-rewr-sel (if calc-rewr-sel t (nth 1 expr)))
107           (nth 1 expr))
108       (cons (car expr)
109             (mapcar 'calc-locate-select-marker (cdr expr))))))
110
111
112
113 (defun calc-rewrite (rules-str many)
114   (interactive "sRewrite rule(s): \nP")
115   (calc-slow-wrapper
116    (let (n rules expr)
117      (if (or (null rules-str) (equal rules-str "") (equal rules-str "$"))
118          (setq expr (calc-top-n 2)
119                rules (calc-top-n 1 t)
120                n 2)
121        (setq rules (if (stringp rules-str)
122                        (math-read-exprs rules-str) rules-str))
123        (if (eq (car-safe rules) 'error)
124            (error "Bad format in expression: %s" (nth 1 rules)))
125        (if (= (length rules) 1)
126            (setq rules (car rules))
127          (setq rules (cons 'vec rules)))
128        (or (memq (car-safe rules) '(vec var calcFunc-assign
129                                         calcFunc-condition))
130            (let ((rhs (math-read-expr
131                        (read-string (concat "Rewrite from:    " rules-str
132                                             " to: ")))))
133              (if (eq (car-safe rhs) 'error)
134                  (error "Bad format in expression: %s" (nth 1 rhs)))
135              (setq rules (list 'calcFunc-assign rules rhs))))
136        (or (eq (car-safe rules) 'var)
137            (calc-record rules "rule"))
138        (setq expr (calc-top-n 1)
139              n 1))
140      (if (eq many 0)
141          (setq many '(var inf var-inf))
142        (if many (setq many (prefix-numeric-value many))))
143      (setq expr (calc-normalize (math-rewrite expr rules many)))
144      (let (calc-rewr-sel)
145        (setq expr (calc-locate-select-marker expr)))
146      (calc-pop-push-record-list n "rwrt" (list expr)))
147    (calc-handle-whys)))
148
149 (defun calc-match (pat &optional interactive)
150   (interactive "sPattern: \np")
151   (calc-slow-wrapper
152    (let (n expr)
153      (if (or (null pat) (equal pat "") (equal pat "$"))
154          (setq expr (calc-top-n 2)
155                pat (calc-top-n 1)
156                n 2)
157        (setq pat (if (stringp pat) (math-read-expr pat) pat))
158        (if (eq (car-safe pat) 'error)
159            (error "Bad format in expression: %s" (nth 1 pat)))
160        (if (not (eq (car-safe pat) 'var))
161            (calc-record pat "pat"))
162        (setq expr (calc-top-n 1)
163              n 1))
164      (or (math-vectorp expr) (error "Argument must be a vector"))
165      (if (calc-is-inverse)
166          (calc-enter-result n "mtcn" (math-match-patterns pat expr t))
167        (calc-enter-result n "mtch" (math-match-patterns pat expr nil))))))
168
169
170 (defvar math-mt-many)
171
172 ;; The variable math-rewrite-whole-expr is local to math-rewrite,
173 ;; but is used by math-rewrite-phase
174 (defvar math-rewrite-whole-expr)
175
176 (defun math-rewrite (math-rewrite-whole-expr rules &optional math-mt-many)
177   (let* ((crules (math-compile-rewrites rules))
178          (heads (math-rewrite-heads math-rewrite-whole-expr))
179          (trace-buffer (get-buffer "*Trace*"))
180          (calc-display-just 'center)
181          (calc-display-origin 39)
182          (calc-line-breaking 78)
183          (calc-line-numbering nil)
184          (calc-show-selections t)
185          (calc-why nil)
186          (math-mt-func (function
187                         (lambda (x)
188                           (let ((result (math-apply-rewrites x (cdr crules)
189                                                              heads crules)))
190                             (if result
191                                 (progn
192                                   (if trace-buffer
193                                       (let ((fmt (math-format-stack-value
194                                                   (list result nil nil))))
195                                         (save-excursion
196                                           (set-buffer trace-buffer)
197                                           (insert "\nrewrite to\n" fmt "\n"))))
198                                   (setq heads (math-rewrite-heads result heads t))))
199                             result)))))
200     (if trace-buffer
201         (let ((fmt (math-format-stack-value (list math-rewrite-whole-expr nil nil))))
202           (save-excursion
203             (set-buffer trace-buffer)
204             (setq truncate-lines t)
205             (goto-char (point-max))
206             (insert "\n\nBegin rewriting\n" fmt "\n"))))
207     (or math-mt-many (setq math-mt-many (or (nth 1 (car crules))
208                                     math-rewrite-default-iters)))
209     (if (equal math-mt-many '(var inf var-inf)) (setq math-mt-many 1000000))
210     (if (equal math-mt-many '(neg (var inf var-inf))) (setq math-mt-many -1000000))
211     (math-rewrite-phase (nth 3 (car crules)))
212     (if trace-buffer
213         (let ((fmt (math-format-stack-value (list math-rewrite-whole-expr nil nil))))
214           (save-excursion
215             (set-buffer trace-buffer)
216             (insert "\nDone rewriting"
217                     (if (= math-mt-many 0) " (reached iteration limit)" "")
218                     ":\n" fmt "\n"))))
219     math-rewrite-whole-expr))
220
221 (defun math-rewrite-phase (sched)
222   (while (and sched (/= math-mt-many 0))
223     (if (listp (car sched))
224         (while (let ((save-expr math-rewrite-whole-expr))
225                  (math-rewrite-phase (car sched))
226                  (not (equal math-rewrite-whole-expr save-expr))))
227       (if (symbolp (car sched))
228           (progn
229             (setq math-rewrite-whole-expr
230                   (math-normalize (list (car sched) math-rewrite-whole-expr)))
231             (if trace-buffer
232                 (let ((fmt (math-format-stack-value
233                             (list math-rewrite-whole-expr nil nil))))
234                   (save-excursion
235                     (set-buffer trace-buffer)
236                     (insert "\ncall "
237                             (substring (symbol-name (car sched)) 9)
238                             ":\n" fmt "\n")))))
239         (let ((math-rewrite-phase (car sched)))
240           (if trace-buffer
241               (save-excursion
242                 (set-buffer trace-buffer)
243                 (insert (format "\n(Phase %d)\n" math-rewrite-phase))))
244           (while (let ((save-expr math-rewrite-whole-expr))
245                    (setq math-rewrite-whole-expr (math-normalize
246                                      (math-map-tree-rec math-rewrite-whole-expr)))
247                    (not (equal math-rewrite-whole-expr save-expr)))))))
248     (setq sched (cdr sched))))
249
250 (defun calcFunc-rewrite (expr rules &optional many)
251   (or (null many) (integerp many)
252       (equal many '(var inf var-inf)) (equal many '(neg (var inf var-inf)))
253       (math-reject-arg many 'fixnump))
254   (condition-case err
255       (math-rewrite expr rules (or many 1))
256     (error (math-reject-arg rules (nth 1 err)))))
257
258 (defun calcFunc-match (pat vec)
259   (or (math-vectorp vec) (math-reject-arg vec 'vectorp))
260   (condition-case err
261       (math-match-patterns pat vec nil)
262     (error (math-reject-arg pat (nth 1 err)))))
263
264 (defun calcFunc-matchnot (pat vec)
265   (or (math-vectorp vec) (math-reject-arg vec 'vectorp))
266   (condition-case err
267       (math-match-patterns pat vec t)
268     (error (math-reject-arg pat (nth 1 err)))))
269
270 (defun math-match-patterns (pat vec &optional not-flag)
271   (let ((newvec nil)
272         (crules (math-compile-patterns pat)))
273     (while (setq vec (cdr vec))
274       (if (eq (not (math-apply-rewrites (car vec) crules))
275               not-flag)
276           (setq newvec (cons (car vec) newvec))))
277     (cons 'vec (nreverse newvec))))
278
279 (defun calcFunc-matches (expr pat)
280   (condition-case err
281       (if (math-apply-rewrites expr (math-compile-patterns pat))
282           1
283         0)
284     (error (math-reject-arg pat (nth 1 err)))))
285
286 (defun calcFunc-vmatches (expr pat)
287   (condition-case err
288       (or (math-apply-rewrites expr (math-compile-patterns pat))
289           0)
290     (error (math-reject-arg pat (nth 1 err)))))
291
292
293
294 ;;; A compiled rule set is an a-list of entries whose cars are functors,
295 ;;; and whose cdrs are lists of rules.  If there are rules with no
296 ;;; well-defined head functor, they are included on all lists and also
297 ;;; on an extra list whose car is nil.
298 ;;;
299 ;;; The first entry in the a-list is of the form (schedule A B C ...).
300 ;;;
301 ;;; Rule list entries take the form (regs prog head phases), where:
302 ;;;
303 ;;;   regs   is a vector of match registers.
304 ;;;
305 ;;;   prog   is a match program (see below).
306 ;;;
307 ;;;   head   is a rare function name appearing in the rule body (but not the
308 ;;;          head of the whole rule), or nil if none.
309 ;;;
310 ;;;   phases is a list of phase numbers for which the rule is enabled.
311 ;;;
312 ;;; A match program is a list of match instructions.
313 ;;;
314 ;;; In the following, "part" is a register number that contains the
315 ;;; subexpression to be operated on.
316 ;;;
317 ;;; Register 0 is the whole expression being matched.  The others are
318 ;;; meta-variables in the pattern, temporaries used for matching and
319 ;;; backtracking, and constant expressions.
320 ;;;
321 ;;; (same part reg)
322 ;;;         The selected part must be math-equal to the contents of "reg".
323 ;;;
324 ;;; (same-neg part reg)
325 ;;;         The selected part must be math-equal to the negative of "reg".
326 ;;;
327 ;;; (copy part reg)
328 ;;;         The selected part is copied into "reg".  (Rarely used.)
329 ;;;
330 ;;; (copy-neg part reg)
331 ;;;         The negative of the selected part is copied into "reg".
332 ;;;
333 ;;; (integer part)
334 ;;;         The selected part must be an integer.
335 ;;;
336 ;;; (real part)
337 ;;;         The selected part must be a real.
338 ;;;
339 ;;; (constant part)
340 ;;;         The selected part must be a constant.
341 ;;;
342 ;;; (negative part)
343 ;;;         The selected part must "look" negative.
344 ;;;
345 ;;; (rel part op reg)
346 ;;;         The selected part must satisfy "part op reg", where "op"
347 ;;;         is one of the 6 relational ops, and "reg" is a register.
348 ;;;
349 ;;; (mod part modulo value)
350 ;;;         The selected part must satisfy "part % modulo = value", where
351 ;;;         "modulo" and "value" are constants.
352 ;;;
353 ;;; (func part head reg1 reg2 ... regn)
354 ;;;         The selected part must be an n-ary call to function "head".
355 ;;;         The arguments are stored in "reg1" through "regn".
356 ;;;
357 ;;; (func-def part head defs reg1 reg2 ... regn)
358 ;;;         The selected part must be an n-ary call to function "head".
359 ;;;         "Defs" is a list of value/register number pairs for default args.
360 ;;;         If a match, assign default values to registers and then skip
361 ;;;         immediately over any following "func-def" instructions and
362 ;;;         the following "func" instruction.  If wrong number of arguments,
363 ;;;         proceed to the following "func-def" or "func" instruction.
364 ;;;
365 ;;; (func-opt part head defs reg1)
366 ;;;         Like func-def with "n=1", except that if the selected part is
367 ;;;         not a call to "head", then the part itself successfully matches
368 ;;;         "reg1" (and the defaults are assigned).
369 ;;;
370 ;;; (try part heads mark reg1 [def])
371 ;;;         The selected part must be a function of the correct type which is
372 ;;;         associative and/or commutative.  "Heads" is a list of acceptable
373 ;;;         types.  An initial assignment of arguments to "reg1" is tried.
374 ;;;         If the program later fails, it backtracks to this instruction
375 ;;;         and tries other assignments of arguments to "reg1".
376 ;;;         If "def" exists and normal matching fails, backtrack and assign
377 ;;;         "part" to "reg1", and "def" to "reg2" in the following "try2".
378 ;;;         The "mark" is a vector of size 5; only "mark[3-4]" are initialized.
379 ;;;         "mark[0]" points to the argument list; "mark[1]" points to the
380 ;;;         current argument; "mark[2]" is 0 if there are two arguments,
381 ;;;         1 if reg1 is matching single arguments, 2 if reg2 is matching
382 ;;;         single arguments (a+b+c+d is never split as (a+b)+(c+d)), or
383 ;;;         3 if reg2 is matching "def"; "mark[3]" is 0 if the function must
384 ;;;         have two arguments, 1 if phase-2 can be skipped, 2 if full
385 ;;;         backtracking is necessary; "mark[4]" is t if the arguments have
386 ;;;         been switched from the order given in the original pattern.
387 ;;;
388 ;;; (try2 try reg2)
389 ;;;         Every "try" will be followed by a "try2" whose "try" field is
390 ;;;         a pointer to the corresponding "try".  The arguments which were
391 ;;;         not stored in "reg1" by that "try" are now stored in "reg2".
392 ;;;
393 ;;; (alt instr nil mark)
394 ;;;         Basic backtracking.  Execute the instruction sequence "instr".
395 ;;;         If this fails, back up and execute following the "alt" instruction.
396 ;;;         The "mark" must be the vector "[nil nil 4]".  The "instr" sequence
397 ;;;         should execute "end-alt" at the end.
398 ;;;
399 ;;; (end-alt ptr)
400 ;;;         Register success of the first alternative of a previous "alt".
401 ;;;         "Ptr" is a pointer to the next instruction following that "alt".
402 ;;;
403 ;;; (apply part reg1 reg2)
404 ;;;         The selected part must be a function call.  The functor
405 ;;;         (as a variable name) is stored in "reg1"; the arguments
406 ;;;         (as a vector) are stored in "reg2".
407 ;;;
408 ;;; (cons part reg1 reg2)
409 ;;;         The selected part must be a nonempty vector.  The first element
410 ;;;         of the vector is stored in "reg1"; the rest of the vector
411 ;;;         (as another vector) is stored in "reg2".
412 ;;;
413 ;;; (rcons part reg1 reg2)
414 ;;;         The selected part must be a nonempty vector.  The last element
415 ;;;         of the vector is stored in "reg2"; the rest of the vector
416 ;;;         (as another vector) is stored in "reg1".
417 ;;;
418 ;;; (select part reg)
419 ;;;         If the selected part is a unary call to function "select", its
420 ;;;         argument is stored in "reg"; otherwise (provided this is an `a r'
421 ;;;         and not a `g r' command) the selected part is stored in "reg".
422 ;;;
423 ;;; (cond expr)
424 ;;;         The "expr", with registers substituted, must simplify to
425 ;;;         a non-zero value.
426 ;;;
427 ;;; (let reg expr)
428 ;;;         Evaluate "expr" and store the result in "reg".  Always succeeds.
429 ;;;
430 ;;; (done rhs remember)
431 ;;;         Rewrite the expression to "rhs", with register substituted.
432 ;;;         Normalize; if the result is different from the original
433 ;;;         expression, the match has succeeded.  This is the last
434 ;;;         instruction of every program.  If "remember" is non-nil,
435 ;;;         record the result of the match as a new literal rule.
436
437
438 ;;; Pseudo-functions related to rewrites:
439 ;;;
440 ;;;  In patterns:  quote, plain, condition, opt, apply, cons, select
441 ;;;
442 ;;;  In righthand sides:  quote, plain, eval, evalsimp, evalextsimp,
443 ;;;                       apply, cons, select
444 ;;;
445 ;;;  In conditions:  let + same as for righthand sides
446
447 ;;; Some optimizations that would be nice to have:
448 ;;;
449 ;;;  * Merge registers with disjoint lifetimes.
450 ;;;  * Merge constant registers with equivalent values.
451 ;;;
452 ;;;  * If an argument of a commutative op math-depends neither on the
453 ;;;    rest of the pattern nor on any of the conditions, then no backtracking
454 ;;;    should be done for that argument.  (This won't apply to very many
455 ;;;    cases.)
456 ;;;
457 ;;;  * If top functor is "select", and its argument is a unique function,
458 ;;;    add the rule to the lists for both "select" and that function.
459 ;;;    (Currently rules like this go on the "nil" list.)
460 ;;;    Same for "func-opt" functions.  (Though not urgent for these.)
461 ;;;
462 ;;;  * Shouldn't evaluate a "let" condition until the end, or until it
463 ;;;    would enable another condition to be evaluated.
464 ;;;
465
466 ;;; Some additional features to add / things to think about:
467 ;;;
468 ;;;  * Figure out what happens to "a +/- b" and "a +/- opt(b)".
469 ;;;
470 ;;;  * Same for interval forms.
471 ;;;
472 ;;;  * Have a name(v,pat) pattern which matches pat, and gives the
473 ;;;    whole match the name v.  Beware of circular structures!
474 ;;;
475
476 (defun math-compile-patterns (pats)
477   (if (and (eq (car-safe pats) 'var)
478            (calc-var-value (nth 2 pats)))
479       (let ((prop (get (nth 2 pats) 'math-pattern-cache)))
480         (or prop
481             (put (nth 2 pats) 'math-pattern-cache (setq prop (list nil))))
482         (or (eq (car prop) (symbol-value (nth 2 pats)))
483             (progn
484               (setcdr prop (math-compile-patterns
485                             (symbol-value (nth 2 pats))))
486               (setcar prop (symbol-value (nth 2 pats)))))
487         (cdr prop))
488     (let ((math-rewrite-whole t))
489       (cdr (math-compile-rewrites (cons
490                                    'vec
491                                    (mapcar (function (lambda (x)
492                                                        (list 'vec x t)))
493                                            (if (eq (car-safe pats) 'vec)
494                                                (cdr pats)
495                                              (list pats)))))))))
496
497 (defvar math-rewrite-whole nil)
498 (defvar math-make-import-list nil)
499
500 ;; The variable math-import-list is local to part of math-compile-rewrites,
501 ;; but is also used in a different part, and so the local version could
502 ;; be affected by the non-local version when math-compile-rewrites calls itself.
503 (defvar math-import-list nil)
504
505 ;; The variables math-regs, math-num-regs, math-prog-last, math-bound-vars,
506 ;; math-conds, math-copy-neg, math-rhs, math-pattern, math-remembering and
507 ;; math-aliased-vars are local to math-compile-rewrites,
508 ;; but are used by many functions math-rwcomp-*, which are called by
509 ;; math-compile-rewrites.
510 (defvar math-regs)
511 (defvar math-num-regs)
512 (defvar math-prog-last)
513 (defvar math-bound-vars)
514 (defvar math-conds)
515 (defvar math-copy-neg)
516 (defvar math-rhs)
517 (defvar math-pattern)
518 (defvar math-remembering)
519 (defvar math-aliased-vars)
520
521 (defun math-compile-rewrites (rules &optional name)
522   (if (eq (car-safe rules) 'var)
523       (let ((prop (get (nth 2 rules) 'math-rewrite-cache))
524             (math-import-list nil)
525             (math-make-import-list t)
526             p)
527         (or (calc-var-value (nth 2 rules))
528             (error "Rules variable %s has no stored value" (nth 1 rules)))
529         (or prop
530             (put (nth 2 rules) 'math-rewrite-cache
531                  (setq prop (list (list (cons (nth 2 rules) nil))))))
532         (setq p (car prop))
533         (while (and p (eq (symbol-value (car (car p))) (cdr (car p))))
534           (setq p (cdr p)))
535         (or (null p)
536             (progn
537               (message "Compiling rule set %s..." (nth 1 rules))
538               (setcdr prop (math-compile-rewrites
539                             (symbol-value (nth 2 rules))
540                             (nth 2 rules)))
541               (message "Compiling rule set %s...done" (nth 1 rules))
542               (setcar prop (cons (cons (nth 2 rules)
543                                        (symbol-value (nth 2 rules)))
544                                  math-import-list))))
545         (cdr prop))
546     (if (or (not (eq (car-safe rules) 'vec))
547             (and (memq (length rules) '(3 4))
548                  (let ((p rules))
549                    (while (and (setq p (cdr p))
550                                (memq (car-safe (car p))
551                                      '(vec
552                                        calcFunc-assign
553                                        calcFunc-condition
554                                        calcFunc-import
555                                        calcFunc-phase
556                                        calcFunc-schedule
557                                        calcFunc-iterations))))
558                    p)))
559         (setq rules (list rules))
560       (setq rules (cdr rules)))
561     (if (assq 'calcFunc-import rules)
562         (let ((pp (setq rules (copy-sequence rules)))
563               p part)
564           (while (setq p (car (cdr pp)))
565             (if (eq (car-safe p) 'calcFunc-import)
566                 (progn
567                   (setcdr pp (cdr (cdr pp)))
568                   (or (and (eq (car-safe (nth 1 p)) 'var)
569                            (setq part (calc-var-value (nth 2 (nth 1 p))))
570                            (memq (car-safe part) '(vec
571                                                    calcFunc-assign
572                                                    calcFunc-condition)))
573                       (error "Argument of import() must be a rules variable"))
574                   (if math-make-import-list
575                       (setq math-import-list
576                             (cons (cons (nth 2 (nth 1 p))
577                                         (symbol-value (nth 2 (nth 1 p))))
578                                   math-import-list)))
579                   (while (setq p (cdr (cdr p)))
580                     (or (cdr p)
581                         (error "import() must have odd number of arguments"))
582                     (setq part (math-rwcomp-substitute part
583                                                        (car p) (nth 1 p))))
584                   (if (eq (car-safe part) 'vec)
585                       (setq part (cdr part))
586                     (setq part (list part)))
587                   (setcdr pp (append part (cdr pp))))
588               (setq pp (cdr pp))))))
589     (let ((rule-set nil)
590           (all-heads nil)
591           (nil-rules nil)
592           (rule-count 0)
593           (math-schedule nil)
594           (math-iterations nil)
595           (math-phases nil)
596           (math-all-phases nil)
597           (math-remembering nil)
598           math-pattern math-rhs math-conds)
599       (while rules
600         (cond
601          ((and (eq (car-safe (car rules)) 'calcFunc-iterations)
602                (= (length (car rules)) 2))
603           (or (integerp (nth 1 (car rules)))
604               (equal (nth 1 (car rules)) '(var inf var-inf))
605               (equal (nth 1 (car rules)) '(neg (var inf var-inf)))
606               (error "Invalid argument for iterations(n)"))
607           (or math-iterations
608               (setq math-iterations (nth 1 (car rules)))))
609          ((eq (car-safe (car rules)) 'calcFunc-schedule)
610           (or math-schedule
611               (setq math-schedule (math-parse-schedule (cdr (car rules))))))
612          ((eq (car-safe (car rules)) 'calcFunc-phase)
613           (setq math-phases (cdr (car rules)))
614           (if (equal math-phases '((var all var-all)))
615               (setq math-phases nil))
616           (let ((p math-phases))
617             (while p
618               (or (integerp (car p))
619                   (error "Phase numbers must be small integers"))
620               (or (memq (car p) math-all-phases)
621                   (setq math-all-phases (cons (car p) math-all-phases)))
622               (setq p (cdr p)))))
623          ((or (and (eq (car-safe (car rules)) 'vec)
624                    (cdr (cdr (car rules)))
625                    (not (nthcdr 4 (car rules)))
626                    (setq math-conds (nth 3 (car rules))
627                          math-rhs (nth 2 (car rules))
628                          math-pattern (nth 1 (car rules))))
629               (progn
630                 (setq math-conds nil
631                       math-pattern (car rules))
632                 (while (and (eq (car-safe math-pattern) 'calcFunc-condition)
633                             (= (length math-pattern) 3))
634                   (let ((cond (nth 2 math-pattern)))
635                     (setq math-conds (if math-conds
636                                          (list 'calcFunc-land math-conds cond)
637                                        cond)
638                           math-pattern (nth 1 math-pattern))))
639                 (and (eq (car-safe math-pattern) 'calcFunc-assign)
640                      (= (length math-pattern) 3)
641                      (setq math-rhs (nth 2 math-pattern)
642                            math-pattern (nth 1 math-pattern)))))
643           (let* ((math-prog (list nil))
644                  (math-prog-last math-prog)
645                  (math-num-regs 1)
646                  (math-regs (list (list nil 0 nil nil)))
647                  (math-bound-vars nil)
648                  (math-aliased-vars nil)
649                  (math-copy-neg nil))
650             (setq math-conds (and math-conds (math-flatten-lands math-conds)))
651             (math-rwcomp-pattern math-pattern 0)
652             (while math-conds
653               (let ((expr (car math-conds)))
654                 (setq math-conds (cdr math-conds))
655                 (math-rwcomp-cond-instr expr)))
656             (math-rwcomp-instr 'done
657                                (if (eq math-rhs t)
658                                    (cons 'vec
659                                          (delq
660                                           nil
661                                           (nreverse
662                                            (mapcar
663                                             (function
664                                              (lambda (v)
665                                                (and (car v)
666                                                     (list
667                                                      'calcFunc-assign
668                                                      (math-build-var-name
669                                                       (car v))
670                                                      (math-rwcomp-register-expr
671                                                       (nth 1 v))))))
672                                             math-regs))))
673                                  (math-rwcomp-match-vars math-rhs))
674                                math-remembering)
675             (setq math-prog (cdr math-prog))
676             (let* ((heads (math-rewrite-heads math-pattern))
677                    (rule (list (vconcat
678                                 (nreverse
679                                  (mapcar (function (lambda (x) (nth 3 x)))
680                                          math-regs)))
681                                math-prog
682                                heads
683                                math-phases))
684                    (head (and (not (Math-primp math-pattern))
685                               (not (and (eq (car (car math-prog)) 'try)
686                                         (nth 5 (car math-prog))))
687                               (not (memq (car (car math-prog)) '(func-opt
688                                                                  apply
689                                                                  select
690                                                                  alt)))
691                               (if (memq (car (car math-prog)) '(func
692                                                                 func-def))
693                                   (nth 2 (car math-prog))
694                                 (if (eq (car math-pattern) 'calcFunc-quote)
695                                     (car-safe (nth 1 math-pattern))
696                                   (car math-pattern))))))
697               (let (found)
698                 (while heads
699                   (if (setq found (assq (car heads) all-heads))
700                       (setcdr found (1+ (cdr found)))
701                     (setq all-heads (cons (cons (car heads) 1) all-heads)))
702                   (setq heads (cdr heads))))
703               (if (eq head '-) (setq head '+))
704               (if (memq head '(calcFunc-cons calcFunc-rcons)) (setq head 'vec))
705               (if head
706                   (progn
707                     (nconc (or (assq head rule-set)
708                                (car (setq rule-set (cons (cons head
709                                                                (copy-sequence
710                                                                 nil-rules))
711                                                          rule-set))))
712                            (list rule))
713                     (if (eq head '*)
714   &nbs