close Warning: Can't synchronize with repository "(default)" (The repository directory has changed, you should resynchronize the repository with: trac-admin $ENV repository resync '(default)'). Look in the Trac log for more information.

source: branches/f4grobner/grobner.lisp@ 70

Last change on this file since 70 was 70, checked in by Marek Rychlik, 10 years ago

* empty log message *

File size: 26.5 KB
Line 
1;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*-
2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3;;;
4;;; Copyright (C) 1999, 2002, 2009 Marek Rychlik <rychlik@u.arizona.edu>
5;;;
6;;; This program is free software; you can redistribute it and/or modify
7;;; it under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 2 of the License, or
9;;; (at your option) any later version.
10;;;
11;;; This program is distributed in the hope that it will be useful,
12;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with this program; if not, write to the Free Software
18;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19;;;
20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
21
22(in-package :maxima)
23
24(macsyma-module cgb-maxima)
25
26(eval-when
27 #+gcl (load eval)
28 #-gcl (:load-toplevel :execute)
29 (format t "~&Loading maxima-grobner ~a ~a~%"
30 "$Revision: 2.0 $" "$Date: 2015/06/02 0:34:17 $"))
31
32;;FUNCTS is loaded because it contains the definition of LCM
33($load "functs")
34
35
36
37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
38;;
39;; Global switches
40;; (Can be used in Maxima just fine)
41;;
42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
43
44(defmvar $poly_monomial_order '$lex
45 "This switch controls which monomial order is used in polynomial
46and Grobner basis calculations. If not set, LEX will be used")
47
48(defmvar $poly_coefficient_ring '$expression_ring
49 "This switch indicates the coefficient ring of the polynomials
50that will be used in grobner calculations. If not set, Maxima's
51general expression ring will be used. This variable may be set
52to RING_OF_INTEGERS if desired.")
53
54(defmvar $poly_primary_elimination_order nil
55 "Name of the default order for eliminated variables in elimination-based functions.
56If not set, LEX will be used.")
57
58(defmvar $poly_secondary_elimination_order nil
59 "Name of the default order for kept variables in elimination-based functions.
60If not set, LEX will be used.")
61
62(defmvar $poly_elimination_order nil
63 "Name of the default elimination order used in elimination calculations.
64If set, it overrides the settings in variables POLY_PRIMARY_ELIMINATION_ORDER
65and SECONDARY_ELIMINATION_ORDER. The user must ensure that this is a true
66elimination order valid for the number of eliminated variables.")
67
68(defmvar $poly_return_term_list nil
69 "If set to T, all functions in this package will return each polynomial as a
70list of terms in the current monomial order rather than a Maxima general expression.")
71
72(defmvar $poly_grobner_debug nil
73 "If set to TRUE, produce debugging and tracing output.")
74
75(defmvar $poly_grobner_algorithm '$buchberger
76 "The name of the algorithm used to find grobner bases.")
77
78(defmvar $poly_top_reduction_only nil
79 "If not FALSE, use top reduction only whenever possible.
80Top reduction means that division algorithm stops after the first reduction.")
81
82
83
84;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
85;;
86;; Coefficient ring operations
87;;
88;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
89;;
90;; These are ALL operations that are performed on the coefficients by
91;; the package, and thus the coefficient ring can be changed by merely
92;; redefining these operations.
93;;
94;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
95
96(defstruct (ring)
97 (parse #'identity :type function)
98 (unit #'identity :type function)
99 (zerop #'identity :type function)
100 (add #'identity :type function)
101 (sub #'identity :type function)
102 (uminus #'identity :type function)
103 (mul #'identity :type function)
104 (div #'identity :type function)
105 (lcm #'identity :type function)
106 (ezgcd #'identity :type function)
107 (gcd #'identity :type function))
108
109(defparameter *ring-of-integers*
110 (make-ring
111 :parse #'identity
112 :unit #'(lambda () 1)
113 :zerop #'zerop
114 :add #'+
115 :sub #'-
116 :uminus #'-
117 :mul #'*
118 :div #'/
119 :lcm #'lcm
120 :ezgcd #'(lambda (x y &aux (c (gcd x y))) (values c (/ x c) (/ y c)))
121 :gcd #'gcd)
122 "The ring of integers.")
123
124
125
126;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
127;;
128;; This is how we perform operations on coefficients
129;; using Maxima functions.
130;;
131;; Functions and macros dealing with internal representation structure
132;;
133;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
134
135
136
137
138;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
139;;
140;; Low-level polynomial arithmetic done on
141;; lists of terms
142;;
143;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
144
145(defmacro termlist-lt (p) `(car ,p))
146(defun termlist-lm (p) (term-monom (termlist-lt p)))
147(defun termlist-lc (p) (term-coeff (termlist-lt p)))
148
149(define-modify-macro scalar-mul (c) coeff-mul)
150
151(defun scalar-times-termlist (ring c p)
152 "Multiply scalar C by a polynomial P. This function works
153even if there are divisors of 0."
154 (mapcan
155 #'(lambda (term)
156 (let ((c1 (funcall (ring-mul ring) c (term-coeff term))))
157 (unless (funcall (ring-zerop ring) c1)
158 (list (make-term (term-monom term) c1)))))
159 p))
160
161
162(defun term-mul (ring term1 term2)
163 "Returns (LIST TERM) wheter TERM is the product of the terms TERM1 TERM2,
164or NIL when the product is 0. This definition takes care of divisors of 0
165in the coefficient ring."
166 (let ((c (funcall (ring-mul ring) (term-coeff term1) (term-coeff term2))))
167 (unless (funcall (ring-zerop ring) c)
168 (list (make-term (monom-mul (term-monom term1) (term-monom term2)) c)))))
169
170(defun term-times-termlist (ring term f)
171 (declare (type ring ring))
172 (mapcan #'(lambda (term-f) (term-mul ring term term-f)) f))
173
174(defun termlist-times-term (ring f term)
175 (mapcan #'(lambda (term-f) (term-mul ring term-f term)) f))
176
177(defun monom-times-term (m term)
178 (make-term (monom-mul m (term-monom term)) (term-coeff term)))
179
180(defun monom-times-termlist (m f)
181 (cond
182 ((null f) nil)
183 (t
184 (mapcar #'(lambda (x) (monom-times-term m x)) f))))
185
186(defun termlist-uminus (ring f)
187 (mapcar #'(lambda (x)
188 (make-term (term-monom x) (funcall (ring-uminus ring) (term-coeff x))))
189 f))
190
191(defun termlist-add (ring p q)
192 (declare (type list p q))
193 (do (r)
194 ((cond
195 ((endp p)
196 (setf r (revappend r q)) t)
197 ((endp q)
198 (setf r (revappend r p)) t)
199 (t
200 (multiple-value-bind
201 (lm-greater lm-equal)
202 (monomial-order (termlist-lm p) (termlist-lm q))
203 (cond
204 (lm-equal
205 (let ((s (funcall (ring-add ring) (termlist-lc p) (termlist-lc q))))
206 (unless (funcall (ring-zerop ring) s) ;check for cancellation
207 (setf r (cons (make-term (termlist-lm p) s) r)))
208 (setf p (cdr p) q (cdr q))))
209 (lm-greater
210 (setf r (cons (car p) r)
211 p (cdr p)))
212 (t (setf r (cons (car q) r)
213 q (cdr q)))))
214 nil))
215 r)))
216
217(defun termlist-sub (ring p q)
218 (declare (type list p q))
219 (do (r)
220 ((cond
221 ((endp p)
222 (setf r (revappend r (termlist-uminus ring q)))
223 t)
224 ((endp q)
225 (setf r (revappend r p))
226 t)
227 (t
228 (multiple-value-bind
229 (mgreater mequal)
230 (monomial-order (termlist-lm p) (termlist-lm q))
231 (cond
232 (mequal
233 (let ((s (funcall (ring-sub ring) (termlist-lc p) (termlist-lc q))))
234 (unless (funcall (ring-zerop ring) s) ;check for cancellation
235 (setf r (cons (make-term (termlist-lm p) s) r)))
236 (setf p (cdr p) q (cdr q))))
237 (mgreater
238 (setf r (cons (car p) r)
239 p (cdr p)))
240 (t (setf r (cons (make-term (termlist-lm q) (funcall (ring-uminus ring) (termlist-lc q))) r)
241 q (cdr q)))))
242 nil))
243 r)))
244
245;; Multiplication of polynomials
246;; Non-destructive version
247(defun termlist-mul (ring p q)
248 (cond ((or (endp p) (endp q)) nil) ;p or q is 0 (represented by NIL)
249 ;; If p=p0+p1 and q=q0+q1 then pq=p0q0+p0q1+p1q
250 ((endp (cdr p))
251 (term-times-termlist ring (car p) q))
252 ((endp (cdr q))
253 (termlist-times-term ring p (car q)))
254 (t
255 (let ((head (term-mul ring (termlist-lt p) (termlist-lt q)))
256 (tail (termlist-add ring (term-times-termlist ring (car p) (cdr q))
257 (termlist-mul ring (cdr p) q))))
258 (cond ((null head) tail)
259 ((null tail) head)
260 (t (nconc head tail)))))))
261
262(defun termlist-unit (ring dimension)
263 (declare (fixnum dimension))
264 (list (make-term (make-monom dimension :initial-element 0)
265 (funcall (ring-unit ring)))))
266
267(defun termlist-expt (ring poly n &aux (dim (monom-dimension (termlist-lm poly))))
268 (declare (type fixnum n dim))
269 (cond
270 ((minusp n) (error "termlist-expt: Negative exponent."))
271 ((endp poly) (if (zerop n) (termlist-unit ring dim) nil))
272 (t
273 (do ((k 1 (ash k 1))
274 (q poly (termlist-mul ring q q)) ;keep squaring
275 (p (termlist-unit ring dim) (if (not (zerop (logand k n))) (termlist-mul ring p q) p)))
276 ((> k n) p)
277 (declare (fixnum k))))))
278
279
280
281
282
283
284;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
285;;
286;; Debugging/tracing
287;;
288;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
289(defmacro debug-cgb (&rest args)
290 `(when $poly_grobner_debug (format *terminal-io* ,@args)))
291
292
293
294
295
296;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
297;;
298;; These are provided mostly for debugging purposes To enable
299;; verification of grobner bases with BUCHBERGER-CRITERION, do
300;; (pushnew :grobner-check *features*) and compile/load this file.
301;; With this feature, the calculations will slow down CONSIDERABLY.
302;;
303;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
304
305(defun grobner-test (ring g f)
306 "Test whether G is a Grobner basis and F is contained in G. Return T
307upon success and NIL otherwise."
308 (debug-cgb "~&GROBNER CHECK: ")
309 (let (($poly_grobner_debug nil)
310 (stat1 (buchberger-criterion ring g))
311 (stat2
312 (every #'poly-zerop
313 (makelist (normal-form ring (copy-tree (elt f i)) g nil)
314 (i 0 (1- (length f)))))))
315 (unless stat1 (error "~&Buchberger criterion failed."))
316 (unless stat2
317 (error "~&Original polys not in ideal spanned by Grobner.")))
318 (debug-cgb "~&GROBNER CHECK END")
319 t)
320
321
322;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
323;;
324;; Selection of algorithm and pair heuristic
325;;
326;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
327
328(defun find-grobner-function (algorithm)
329 "Return a function which calculates Grobner basis, based on its
330names. Names currently used are either Lisp symbols, Maxima symbols or
331keywords."
332 (ecase algorithm
333 ((buchberger :buchberger $buchberger) #'buchberger)
334 ((parallel-buchberger :parallel-buchberger $parallel_buchberger) #'parallel-buchberger)
335 ((gebauer-moeller :gebauer_moeller $gebauer_moeller) #'gebauer-moeller)))
336
337(defun grobner (ring f &optional (start 0) (top-reduction-only nil))
338 ;;(setf F (sort F #'< :key #'sugar))
339 (funcall
340 (find-grobner-function $poly_grobner_algorithm)
341 ring f start top-reduction-only))
342
343(defun reduced-grobner (ring f &optional (start 0) (top-reduction-only $poly_top_reduction_only))
344 (reduction ring (grobner ring f start top-reduction-only)))
345
346(defun set-pair-heuristic (method)
347 "Sets up variables *PAIR-KEY-FUNCTION* and *PAIR-ORDER* used
348to determine the priority of critical pairs in the priority queue."
349 (ecase method
350 ((sugar :sugar $sugar)
351 (setf *pair-key-function* #'sugar-pair-key
352 *pair-order* #'sugar-order))
353; ((minimal-mock-spoly :minimal-mock-spoly $minimal_mock_spoly)
354; (setf *pair-key-function* #'mock-spoly
355; *pair-order* #'mock-spoly-order))
356 ((minimal-lcm :minimal-lcm $minimal_lcm)
357 (setf *pair-key-function* #'(lambda (p q)
358 (monom-lcm (poly-lm p) (poly-lm q)))
359 *pair-order* #'reverse-monomial-order))
360 ((minimal-total-degree :minimal-total-degree $minimal_total_degree)
361 (setf *pair-key-function* #'(lambda (p q)
362 (monom-total-degree
363 (monom-lcm (poly-lm p) (poly-lm q))))
364 *pair-order* #'<))
365 ((minimal-length :minimal-length $minimal_length)
366 (setf *pair-key-function* #'(lambda (p q)
367 (+ (poly-length p) (poly-length q)))
368 *pair-order* #'<))))
369
370
371
372
373;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
374;;
375;; Set up the coefficients to be polynomials
376;;
377;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
378
379;; (defun poly-ring (ring vars)
380;; (make-ring
381;; :parse #'(lambda (expr) (poly-eval ring expr vars))
382;; :unit #'(lambda () (poly-unit ring (length vars)))
383;; :zerop #'poly-zerop
384;; :add #'(lambda (x y) (poly-add ring x y))
385;; :sub #'(lambda (x y) (poly-sub ring x y))
386;; :uminus #'(lambda (x) (poly-uminus ring x))
387;; :mul #'(lambda (x y) (poly-mul ring x y))
388;; :div #'(lambda (x y) (poly-exact-divide ring x y))
389;; :lcm #'(lambda (x y) (poly-lcm ring x y))
390;; :ezgcd #'(lambda (x y &aux (gcd (poly-gcd ring x y)))
391;; (values gcd
392;; (poly-exact-divide ring x gcd)
393;; (poly-exact-divide ring y gcd)))
394;; :gcd #'(lambda (x y) (poly-gcd x y))))
395
396
397
398;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
399;;
400;; Conversion from internal to infix form
401;;
402;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
403
404(defun coerce-to-infix (poly-type object vars)
405 (case poly-type
406 (:termlist
407 `(+ ,@(mapcar #'(lambda (term) (coerce-to-infix :term term vars)) object)))
408 (:polynomial
409 (coerce-to-infix :termlist (poly-termlist object) vars))
410 (:poly-list
411 `([ ,@(mapcar #'(lambda (p) (coerce-to-infix :polynomial p vars)) object)))
412 (:term
413 `(* ,(term-coeff object)
414 ,@(mapcar #'(lambda (var power) `(expt ,var ,power))
415 vars (monom-exponents (term-monom object)))))
416 (otherwise
417 object)))
418
419
420
421;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
422;;
423;; Maxima expression ring
424;;
425;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
426
427(defparameter *expression-ring*
428 (make-ring
429 ;;(defun coeff-zerop (expr) (meval1 `(($is) (($equal) ,expr 0))))
430 :parse #'(lambda (expr)
431 (when modulus (setf expr ($rat expr)))
432 expr)
433 :unit #'(lambda () (if modulus ($rat 1) 1))
434 :zerop #'(lambda (expr)
435 ;;When is exactly a maxima expression equal to 0?
436 (cond ((numberp expr)
437 (= expr 0))
438 ((atom expr) nil)
439 (t
440 (case (caar expr)
441 (mrat (eql ($ratdisrep expr) 0))
442 (otherwise (eql ($totaldisrep expr) 0))))))
443 :add #'(lambda (x y) (m+ x y))
444 :sub #'(lambda (x y) (m- x y))
445 :uminus #'(lambda (x) (m- x))
446 :mul #'(lambda (x y) (m* x y))
447 ;;(defun coeff-div (x y) (cadr ($divide x y)))
448 :div #'(lambda (x y) (m// x y))
449 :lcm #'(lambda (x y) (meval1 `((|$LCM|) ,x ,y)))
450 :ezgcd #'(lambda (x y) (apply #'values (cdr ($ezgcd ($totaldisrep x) ($totaldisrep y)))))
451 ;; :gcd #'(lambda (x y) (second ($ezgcd x y)))))
452 :gcd #'(lambda (x y) ($gcd x y))))
453
454(defvar *maxima-ring* *expression-ring*
455 "The ring of coefficients, over which all polynomials
456are assumed to be defined.")
457
458
459;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
460;;
461;; Order utilities
462;;
463;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
464(defun find-order (order)
465 "This function returns the order function bases on its name."
466 (cond
467 ((null order) nil)
468 ((symbolp order)
469 (case order
470 ((lex :lex $lex) #'lex>)
471 ((grlex :grlex $grlex) #'grlex>)
472 ((grevlex :grevlex $grevlex) #'grevlex>)
473 ((invlex :invlex $invlex) #'invlex>)
474 ((elimination-order-1 :elimination-order-1 elimination_order_1) #'elimination-order-1)
475 (otherwise
476 (mtell "~%Warning: Order ~M not found. Using default.~%" order))))
477 (t
478 (mtell "~%Order specification ~M is not recognized. Using default.~%" order)
479 nil)))
480
481(defun find-ring (ring)
482 "This function returns the ring structure bases on input symbol."
483 (cond
484 ((null ring) nil)
485 ((symbolp ring)
486 (case ring
487 ((expression-ring :expression-ring $expression_ring) *expression-ring*)
488 ((ring-of-integers :ring-of-integers $ring_of_integers) *ring-of-integers*)
489 (otherwise
490 (mtell "~%Warning: Ring ~M not found. Using default.~%" ring))))
491 (t
492 (mtell "~%Ring specification ~M is not recognized. Using default.~%" ring)
493 nil)))
494
495(defmacro with-monomial-order ((order) &body body)
496 "Evaluate BODY with monomial order set to ORDER."
497 `(let ((*monomial-order* (or (find-order ,order) *monomial-order*)))
498 . ,body))
499
500(defmacro with-coefficient-ring ((ring) &body body)
501 "Evaluate BODY with coefficient ring set to RING."
502 `(let ((*maxima-ring* (or (find-ring ,ring) *maxima-ring*)))
503 . ,body))
504
505(defmacro with-elimination-orders ((primary secondary elimination-order)
506 &body body)
507 "Evaluate BODY with primary and secondary elimination orders set to PRIMARY and SECONDARY."
508 `(let ((*primary-elimination-order* (or (find-order ,primary) *primary-elimination-order*))
509 (*secondary-elimination-order* (or (find-order ,secondary) *secondary-elimination-order*))
510 (*elimination-order* (or (find-order ,elimination-order) *elimination-order*)))
511 . ,body))
512
513
514
515;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
516;;
517;; Conversion from internal form to Maxima general form
518;;
519;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
520
521(defun maxima-head ()
522 (if $poly_return_term_list
523 '(mlist)
524 '(mplus)))
525
526(defun coerce-to-maxima (poly-type object vars)
527 (case poly-type
528 (:polynomial
529 `(,(maxima-head) ,@(mapcar #'(lambda (term) (coerce-to-maxima :term term vars)) (poly-termlist object))))
530 (:poly-list
531 `((mlist) ,@(mapcar #'(lambda (p) ($ratdisrep (coerce-to-maxima :polynomial p vars))) object)))
532 (:term
533 `((mtimes) ,($ratdisrep (term-coeff object))
534 ,@(mapcar #'(lambda (var power) `((mexpt) ,var ,power))
535 vars (monom-exponents (term-monom object)))))
536 ;; Assumes that Lisp and Maxima logicals coincide
537 (:logical object)
538 (otherwise
539 object)))
540
541
542
543;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
544;;
545;; Macro facility for writing Maxima-level wrappers for
546;; functions operating on internal representation
547;;
548;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
549
550(defmacro with-parsed-polynomials (((maxima-vars &optional (maxima-new-vars nil new-vars-supplied-p))
551 &key (polynomials nil)
552 (poly-lists nil)
553 (poly-list-lists nil)
554 (value-type nil))
555 &body body
556 &aux (vars (gensym))
557 (new-vars (gensym)))
558 `(let ((,vars (coerce-maxima-list ,maxima-vars))
559 ,@(when new-vars-supplied-p
560 (list `(,new-vars (coerce-maxima-list ,maxima-new-vars)))))
561 (coerce-to-maxima
562 ,value-type
563 (with-coefficient-ring ($poly_coefficient_ring)
564 (with-monomial-order ($poly_monomial_order)
565 (with-elimination-orders ($poly_primary_elimination_order
566 $poly_secondary_elimination_order
567 $poly_elimination_order)
568 (let ,(let ((args nil))
569 (dolist (p polynomials args)
570 (setf args (cons `(,p (parse-poly ,p ,vars)) args)))
571 (dolist (p poly-lists args)
572 (setf args (cons `(,p (parse-poly-list ,p ,vars)) args)))
573 (dolist (p poly-list-lists args)
574 (setf args (cons `(,p (parse-poly-list-list ,p ,vars)) args))))
575 . ,body))))
576 ,(if new-vars-supplied-p
577 `(append ,vars ,new-vars)
578 vars))))
579
580(defmacro define-unop (maxima-name fun-name
581 &optional (documentation nil documentation-supplied-p))
582 "Define a MAXIMA-level unary operator MAXIMA-NAME corresponding to unary function FUN-NAME."
583 `(defun ,maxima-name (p vars
584 &aux
585 (vars (coerce-maxima-list vars))
586 (p (parse-poly p vars)))
587 ,@(when documentation-supplied-p (list documentation))
588 (coerce-to-maxima :polynomial (,fun-name *maxima-ring* p) vars)))
589
590(defmacro define-binop (maxima-name fun-name
591 &optional (documentation nil documentation-supplied-p))
592 "Define a MAXIMA-level binary operator MAXIMA-NAME corresponding to binary function FUN-NAME."
593 `(defmfun ,maxima-name (p q vars
594 &aux
595 (vars (coerce-maxima-list vars))
596 (p (parse-poly p vars))
597 (q (parse-poly q vars)))
598 ,@(when documentation-supplied-p (list documentation))
599 (coerce-to-maxima :polynomial (,fun-name *maxima-ring* p q) vars)))
600
601
602
603;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
604;;
605;; Maxima-level interface functions
606;;
607;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
608
609;; Auxillary function for removing zero polynomial
610(defun remzero (plist) (remove #'poly-zerop plist))
611
612;;Simple operators
613
614(define-binop $poly_add poly-add
615 "Adds two polynomials P and Q")
616
617(define-binop $poly_subtract poly-sub
618 "Subtracts a polynomial Q from P.")
619
620(define-binop $poly_multiply poly-mul
621 "Returns the product of polynomials P and Q.")
622
623(define-binop $poly_s_polynomial spoly
624 "Returns the syzygy polynomial (S-polynomial) of two polynomials P and Q.")
625
626(define-unop $poly_primitive_part poly-primitive-part
627 "Returns the polynomial P divided by GCD of its coefficients.")
628
629(define-unop $poly_normalize poly-normalize
630 "Returns the polynomial P divided by the leading coefficient.")
631
632;;Functions
633
634(defmfun $poly_expand (p vars)
635 "This function is equivalent to EXPAND(P) if P parses correctly to a polynomial.
636If the representation is not compatible with a polynomial in variables VARS,
637the result is an error."
638 (with-parsed-polynomials ((vars) :polynomials (p)
639 :value-type :polynomial)
640 p))
641
642(defmfun $poly_expt (p n vars)
643 (with-parsed-polynomials ((vars) :polynomials (p) :value-type :polynomial)
644 (poly-expt *maxima-ring* p n)))
645
646(defmfun $poly_content (p vars)
647 (with-parsed-polynomials ((vars) :polynomials (p))
648 (poly-content *maxima-ring* p)))
649
650(defmfun $poly_pseudo_divide (f fl vars
651 &aux (vars (coerce-maxima-list vars))
652 (f (parse-poly f vars))
653 (fl (parse-poly-list fl vars)))
654 (multiple-value-bind (quot rem c division-count)
655 (poly-pseudo-divide *maxima-ring* f fl)
656 `((mlist)
657 ,(coerce-to-maxima :poly-list quot vars)
658 ,(coerce-to-maxima :polynomial rem vars)
659 ,c
660 ,division-count)))
661
662(defmfun $poly_exact_divide (f g vars)
663 (with-parsed-polynomials ((vars) :polynomials (f g) :value-type :polynomial)
664 (poly-exact-divide *maxima-ring* f g)))
665
666(defmfun $poly_normal_form (f fl vars)
667 (with-parsed-polynomials ((vars) :polynomials (f)
668 :poly-lists (fl)
669 :value-type :polynomial)
670 (normal-form *maxima-ring* f (remzero fl) nil)))
671
672(defmfun $poly_buchberger_criterion (g vars)
673 (with-parsed-polynomials ((vars) :poly-lists (g) :value-type :logical)
674 (buchberger-criterion *maxima-ring* g)))
675
676(defmfun $poly_buchberger (fl vars)
677 (with-parsed-polynomials ((vars) :poly-lists (fl) :value-type :poly-list)
678 (buchberger *maxima-ring* (remzero fl) 0 nil)))
679
680(defmfun $poly_reduction (plist vars)
681 (with-parsed-polynomials ((vars) :poly-lists (plist)
682 :value-type :poly-list)
683 (reduction *maxima-ring* plist)))
684
685(defmfun $poly_minimization (plist vars)
686 (with-parsed-polynomials ((vars) :poly-lists (plist)
687 :value-type :poly-list)
688 (minimization plist)))
689
690(defmfun $poly_normalize_list (plist vars)
691 (with-parsed-polynomials ((vars) :poly-lists (plist)
692 :value-type :poly-list)
693 (poly-normalize-list *maxima-ring* plist)))
694
695(defmfun $poly_grobner (f vars)
696 (with-parsed-polynomials ((vars) :poly-lists (f)
697 :value-type :poly-list)
698 (grobner *maxima-ring* (remzero f))))
699
700(defmfun $poly_reduced_grobner (f vars)
701 (with-parsed-polynomials ((vars) :poly-lists (f)
702 :value-type :poly-list)
703 (reduced-grobner *maxima-ring* (remzero f))))
704
705(defmfun $poly_depends_p (p var mvars
706 &aux (vars (coerce-maxima-list mvars))
707 (pos (position var vars)))
708 (if (null pos)
709 (merror "~%Variable ~M not in the list of variables ~M." var mvars)
710 (poly-depends-p (parse-poly p vars) pos)))
711
712(defmfun $poly_elimination_ideal (flist k vars)
713 (with-parsed-polynomials ((vars) :poly-lists (flist)
714 :value-type :poly-list)
715 (elimination-ideal *maxima-ring* flist k nil 0)))
716
717(defmfun $poly_colon_ideal (f g vars)
718 (with-parsed-polynomials ((vars) :poly-lists (f g) :value-type :poly-list)
719 (colon-ideal *maxima-ring* f g nil)))
720
721(defmfun $poly_ideal_intersection (f g vars)
722 (with-parsed-polynomials ((vars) :poly-lists (f g) :value-type :poly-list)
723 (ideal-intersection *maxima-ring* f g nil)))
724
725(defmfun $poly_lcm (f g vars)
726 (with-parsed-polynomials ((vars) :polynomials (f g) :value-type :polynomial)
727 (poly-lcm *maxima-ring* f g)))
728
729(defmfun $poly_gcd (f g vars)
730 ($first ($divide (m* f g) ($poly_lcm f g vars))))
731
732(defmfun $poly_grobner_equal (g1 g2 vars)
733 (with-parsed-polynomials ((vars) :poly-lists (g1 g2))
734 (grobner-equal *maxima-ring* g1 g2)))
735
736(defmfun $poly_grobner_subsetp (g1 g2 vars)
737 (with-parsed-polynomials ((vars) :poly-lists (g1 g2))
738 (grobner-subsetp *maxima-ring* g1 g2)))
739
740(defmfun $poly_grobner_member (p g vars)
741 (with-parsed-polynomials ((vars) :polynomials (p) :poly-lists (g))
742 (grobner-member *maxima-ring* p g)))
743
744(defmfun $poly_ideal_saturation1 (f p vars)
745 (with-parsed-polynomials ((vars) :poly-lists (f) :polynomials (p)
746 :value-type :poly-list)
747 (ideal-saturation-1 *maxima-ring* f p 0)))
748
749(defmfun $poly_saturation_extension (f plist vars new-vars)
750 (with-parsed-polynomials ((vars new-vars)
751 :poly-lists (f plist)
752 :value-type :poly-list)
753 (saturation-extension *maxima-ring* f plist)))
754
755(defmfun $poly_polysaturation_extension (f plist vars new-vars)
756 (with-parsed-polynomials ((vars new-vars)
757 :poly-lists (f plist)
758 :value-type :poly-list)
759 (polysaturation-extension *maxima-ring* f plist)))
760
761(defmfun $poly_ideal_polysaturation1 (f plist vars)
762 (with-parsed-polynomials ((vars) :poly-lists (f plist)
763 :value-type :poly-list)
764 (ideal-polysaturation-1 *maxima-ring* f plist 0 nil)))
765
766(defmfun $poly_ideal_saturation (f g vars)
767 (with-parsed-polynomials ((vars) :poly-lists (f g)
768 :value-type :poly-list)
769 (ideal-saturation *maxima-ring* f g 0 nil)))
770
771(defmfun $poly_ideal_polysaturation (f ideal-list vars)
772 (with-parsed-polynomials ((vars) :poly-lists (f)
773 :poly-list-lists (ideal-list)
774 :value-type :poly-list)
775 (ideal-polysaturation *maxima-ring* f ideal-list 0 nil)))
776
777(defmfun $poly_lt (f vars)
778 (with-parsed-polynomials ((vars) :polynomials (f) :value-type :polynomial)
779 (make-poly-from-termlist (list (poly-lt f)))))
780
781(defmfun $poly_lm (f vars)
782 (with-parsed-polynomials ((vars) :polynomials (f) :value-type :polynomial)
783 (make-poly-from-termlist (list (make-term (poly-lm f) (funcall (ring-unit *maxima-ring*)))))))
784
Note: See TracBrowser for help on using the repository browser.