| 1 | (defun alist-form (plist vars)
|
---|
| 2 | "Translates an expression PLIST, which should be a list of polynomials
|
---|
| 3 | in variables VARS, to an alist representation of a polynomial.
|
---|
| 4 | It returns the alist. See also PARSE-TO-ALIST."
|
---|
| 5 | (cond
|
---|
| 6 | ((endp plist) nil)
|
---|
| 7 | ((eql (first plist) '[)
|
---|
| 8 | (cons '[ (mapcar #'(lambda (x) (alist-form x vars)) (rest plist))))
|
---|
| 9 | (t
|
---|
| 10 | (assert (eql (car plist) '+))
|
---|
| 11 | (alist-form-1 (rest plist) vars))))
|
---|
| 12 |
|
---|
| 13 | (defun alist-form-1 (p vars
|
---|
| 14 | &aux (ht (make-hash-table
|
---|
| 15 | :test #'equal :size 16))
|
---|
| 16 | stack)
|
---|
| 17 | (dolist (term p)
|
---|
| 18 | (assert (eql (car term) '*))
|
---|
| 19 | (incf (gethash (powers (cddr term) vars) ht 0) (second term)))
|
---|
| 20 | (maphash #'(lambda (key value) (unless (zerop value)
|
---|
| 21 | (push (cons key value) stack))) ht)
|
---|
| 22 | stack)
|
---|
| 23 |
|
---|
| 24 | (defun powers (monom vars
|
---|
| 25 | &aux (tab (pairlis vars (make-list (length vars)
|
---|
| 26 | :initial-element 0))))
|
---|
| 27 | (dolist (e monom (mapcar #'(lambda (v) (cdr (assoc v tab))) vars))
|
---|
| 28 | (assert (equal (first e) '^))
|
---|
| 29 | (assert (integerp (third e)))
|
---|
| 30 | (assert (= (length e) 3))
|
---|
| 31 | (let ((x (assoc (second e) tab)))
|
---|
| 32 | (if (null x) (error "Variable ~a not in the list of variables."
|
---|
| 33 | (second e))
|
---|
| 34 | (incf (cdr x) (third e))))))
|
---|
| 35 |
|
---|
| 36 |
|
---|
| 37 |
|
---|
| 38 | (defun convert-number (number-or-poly n)
|
---|
| 39 | "Returns NUMBER-OR-POLY, if it is a polynomial. If it is a number,
|
---|
| 40 | it converts it to the constant monomial in N variables. If the result
|
---|
| 41 | is a number then convert it to a polynomial in N variables."
|
---|
| 42 | (if (numberp number-or-poly)
|
---|
| 43 | (make-poly-from-termlist (list (make-term (make-monom :dimension n) number-or-poly)))
|
---|
| 44 | number-or-poly))
|
---|
| 45 |
|
---|
| 46 | (defun $poly+ (ring-and-order p q n)
|
---|
| 47 | "Add two polynomials P and Q, where each polynomial is either a
|
---|
| 48 | numeric constant or a polynomial in internal representation. If the
|
---|
| 49 | result is a number then convert it to a polynomial in N variables."
|
---|
| 50 | (poly-add ring-and-order (convert-number p n) (convert-number q n)))
|
---|
| 51 |
|
---|
| 52 | (defun $poly- (ring-and-order p q n)
|
---|
| 53 | "Subtract two polynomials P and Q, where each polynomial is either a
|
---|
| 54 | numeric constant or a polynomial in internal representation. If the
|
---|
| 55 | result is a number then convert it to a polynomial in N variables."
|
---|
| 56 | (poly-sub ring-and-order (convert-number p n) (convert-number q n)))
|
---|
| 57 |
|
---|
| 58 | (defun $minus-poly (ring p n)
|
---|
| 59 | "Negation of P is a polynomial is either a numeric constant or a
|
---|
| 60 | polynomial in internal representation. If the result is a number then
|
---|
| 61 | convert it to a polynomial in N variables."
|
---|
| 62 | (poly-uminus ring (convert-number p n)))
|
---|
| 63 |
|
---|
| 64 | (defun $poly* (ring-and-order p q n)
|
---|
| 65 | "Multiply two polynomials P and Q, where each polynomial is either a
|
---|
| 66 | numeric constant or a polynomial in internal representation. If the
|
---|
| 67 | result is a number then convert it to a polynomial in N variables."
|
---|
| 68 | (poly-mul ring-and-order (convert-number p n) (convert-number q n)))
|
---|
| 69 |
|
---|
| 70 | (defun $poly/ (ring p q)
|
---|
| 71 | "Divide a polynomials P which is either a numeric constant or a
|
---|
| 72 | polynomial in internal representation, by a number Q."
|
---|
| 73 | (if (numberp p)
|
---|
| 74 | (common-lisp:/ p q)
|
---|
| 75 | (scalar-times-poly ring (common-lisp:/ q) p)))
|
---|
| 76 |
|
---|
| 77 | (defun $poly-expt (ring-and-order p l n)
|
---|
| 78 | "Raise polynomial P, which is a polynomial in internal
|
---|
| 79 | representation or a numeric constant, to power L. If P is a number,
|
---|
| 80 | convert the result to a polynomial in N variables."
|
---|
| 81 | (poly-expt ring-and-order (convert-number p n) l))
|
---|
| 82 |
|
---|
| 83 |
|
---|
| 84 | (defun variable-basis (ring n &aux (basis (make-list n)))
|
---|
| 85 | "Generate a list of polynomials X[i], i=0,1,...,N-1."
|
---|
| 86 | (dotimes (i n basis)
|
---|
| 87 | (setf (elt basis i) (make-variable ring n i))))
|
---|
| 88 |
|
---|
| 89 |
|
---|
| 90 | (defun poly-eval-1 (expr vars &optional (ring *ring-of-integers*) (order #'lex>)
|
---|
| 91 | &aux
|
---|
| 92 | (ring-and-order (make-ring-and-order :ring ring :order order))
|
---|
| 93 | (n (length vars))
|
---|
| 94 | (basis (variable-basis ring (length vars))))
|
---|
| 95 | "Evaluate an expression EXPR as polynomial by substituting operators
|
---|
| 96 | + - * expt with corresponding polynomial operators and variables VARS
|
---|
| 97 | with the corresponding polynomials in internal form. We use special
|
---|
| 98 | versions of binary operators $poly+, $poly-, $minus-poly, $poly* and
|
---|
| 99 | $poly-expt which work like the corresponding functions in the POLY
|
---|
| 100 | package, but accept scalars as arguments as well. The result is a
|
---|
| 101 | polynomial in internal form. This operation is somewhat similar to
|
---|
| 102 | the function EXPAND in CAS."
|
---|
| 103 | (cond
|
---|
| 104 | ((numberp expr)
|
---|
| 105 | (cond
|
---|
| 106 | ((zerop expr) NIL)
|
---|
| 107 | (t (make-poly-from-termlist (list (make-term (make-monom :dimension n) expr))))))
|
---|
| 108 | ((symbolp expr)
|
---|
| 109 | (nth (position expr vars) basis))
|
---|
| 110 | ((consp expr)
|
---|
| 111 | (case (car expr)
|
---|
| 112 | (expt
|
---|
| 113 | (if (= (length expr) 3)
|
---|
| 114 | ($poly-expt ring-and-order
|
---|
| 115 | (poly-eval-1 (cadr expr) vars ring order)
|
---|
| 116 | (caddr expr)
|
---|
| 117 | n)
|
---|
| 118 | (error "Too many arguments to EXPT")))
|
---|
| 119 | (/
|
---|
| 120 | (if (and (= (length expr) 3)
|
---|
| 121 | (numberp (caddr expr)))
|
---|
| 122 | ($poly/ ring (cadr expr) (caddr expr))
|
---|
| 123 | (error "The second argument to / must be a number")))
|
---|
| 124 | (otherwise
|
---|
| 125 | (let ((r (mapcar
|
---|
| 126 | #'(lambda (e) (poly-eval-1 e vars ring order))
|
---|
| 127 | (cdr expr))))
|
---|
| 128 | (ecase (car expr)
|
---|
| 129 | (+ (reduce #'(lambda (p q) ($poly+ ring-and-order p q n)) r))
|
---|
| 130 | (-
|
---|
| 131 | (if (endp (cdr r))
|
---|
| 132 | ($minus-poly ring (car r) n)
|
---|
| 133 | ($poly- ring-and-order
|
---|
| 134 | (car r)
|
---|
| 135 | (reduce #'(lambda (p q) ($poly+ ring-and-order p q n)) (cdr r))
|
---|
| 136 | n)))
|
---|
| 137 | (*
|
---|
| 138 | (reduce #'(lambda (p q) ($poly* ring-and-order p q n)) r))
|
---|
| 139 | )))))))
|
---|
| 140 |
|
---|
| 141 |
|
---|
| 142 |
|
---|
| 143 | (defun poly-eval (expr vars &optional (order #'lex>) (ring *ring-of-integers*))
|
---|
| 144 | "Evaluate an expression EXPR, which should be a polynomial
|
---|
| 145 | expression or a list of polynomial expressions (a list of expressions
|
---|
| 146 | marked by prepending keyword :[ to it) given in Lisp prefix notation,
|
---|
| 147 | in variables VARS, which should be a list of symbols. The result of
|
---|
| 148 | the evaluation is a polynomial or a list of polynomials (marked by
|
---|
| 149 | prepending symbol '[) in the internal alist form. This evaluator is
|
---|
| 150 | used by the PARSE package to convert input from strings directly to
|
---|
| 151 | internal form."
|
---|
| 152 | (cond
|
---|
| 153 | ((numberp expr)
|
---|
| 154 | (unless (zerop expr)
|
---|
| 155 | (make-poly-from-termlist
|
---|
| 156 | (list (make-term (make-monom :dimension (length vars)) expr)))))
|
---|
| 157 | ((or (symbolp expr) (not (eq (car expr) :[)))
|
---|
| 158 | (poly-eval-1 expr vars ring order))
|
---|
| 159 | (t (cons '[ (mapcar #'(lambda (p) (poly-eval-1 p vars ring order)) (rest expr))))))
|
---|
| 160 |
|
---|
| 161 |
|
---|