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@ 162

Last change on this file since 162 was 161, checked in by Marek Rychlik, 9 years ago

* empty log message *

File size: 12.0 KB
RevLine 
[1]1;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*-
2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3;;;
[72]4;;; Copyright (C) 1999, 2002, 2009, 2015 Marek Rychlik <rychlik@u.arizona.edu>
[1]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
[135]22(defpackage "GROBNER"
23 (:use :cl))
24
25(in-package :grobner)
26
[1]27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
28;;
29;; Global switches
30;;
[94]31;; Can be used in Maxima just fine, as they observe the
[95]32;; Maxima naming convention, i.e. all names visible at the
[96]33;; Maxima toplevel begin with a '$'.
[94]34;;
[1]35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
36
[97]37(defvar $poly_monomial_order '$lex
[1]38 "This switch controls which monomial order is used in polynomial
39and Grobner basis calculations. If not set, LEX will be used")
40
[97]41(defvar $poly_coefficient_ring '$expression_ring
[1]42 "This switch indicates the coefficient ring of the polynomials
43that will be used in grobner calculations. If not set, Maxima's
44general expression ring will be used. This variable may be set
45to RING_OF_INTEGERS if desired.")
46
[97]47(defvar $poly_primary_elimination_order nil
[1]48 "Name of the default order for eliminated variables in elimination-based functions.
49If not set, LEX will be used.")
50
[97]51(defvar $poly_secondary_elimination_order nil
[1]52 "Name of the default order for kept variables in elimination-based functions.
53If not set, LEX will be used.")
54
[97]55(defvar $poly_elimination_order nil
[1]56 "Name of the default elimination order used in elimination calculations.
57If set, it overrides the settings in variables POLY_PRIMARY_ELIMINATION_ORDER
58and SECONDARY_ELIMINATION_ORDER. The user must ensure that this is a true
59elimination order valid for the number of eliminated variables.")
60
[97]61(defvar $poly_return_term_list nil
[1]62 "If set to T, all functions in this package will return each polynomial as a
63list of terms in the current monomial order rather than a Maxima general expression.")
64
[97]65(defvar $poly_grobner_debug nil
[1]66 "If set to TRUE, produce debugging and tracing output.")
67
[97]68(defvar $poly_grobner_algorithm '$buchberger
[1]69 "The name of the algorithm used to find grobner bases.")
70
[97]71(defvar $poly_top_reduction_only nil
[1]72 "If not FALSE, use top reduction only whenever possible.
73Top reduction means that division algorithm stops after the first reduction.")
74
75
76
77;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
78;;
79;; Coefficient ring operations
80;;
81;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
82;;
83;; These are ALL operations that are performed on the coefficients by
84;; the package, and thus the coefficient ring can be changed by merely
85;; redefining these operations.
86;;
87;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
88
89(defstruct (ring)
90 (parse #'identity :type function)
91 (unit #'identity :type function)
92 (zerop #'identity :type function)
93 (add #'identity :type function)
94 (sub #'identity :type function)
95 (uminus #'identity :type function)
96 (mul #'identity :type function)
97 (div #'identity :type function)
98 (lcm #'identity :type function)
99 (ezgcd #'identity :type function)
100 (gcd #'identity :type function))
101
102(defparameter *ring-of-integers*
103 (make-ring
104 :parse #'identity
105 :unit #'(lambda () 1)
106 :zerop #'zerop
107 :add #'+
108 :sub #'-
109 :uminus #'-
110 :mul #'*
111 :div #'/
112 :lcm #'lcm
113 :ezgcd #'(lambda (x y &aux (c (gcd x y))) (values c (/ x c) (/ y c)))
114 :gcd #'gcd)
115 "The ring of integers.")
[131]116
[125]117(defvar *expression-ring* *ring-of-integers*
118 "The ring of coefficients, over which all polynomials are assumed to
[124]119 be defined.")
[128]120
[129]121(defvar *ratdisrep-fun* #'identity
[124]122 "A function applied to polynomials after conversion to Maxima representation.")
[1]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;; Debugging/tracing
139;;
140;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
141(defmacro debug-cgb (&rest args)
142 `(when $poly_grobner_debug (format *terminal-io* ,@args)))
143
144
145
146;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
147;;
148;; These are provided mostly for debugging purposes To enable
149;; verification of grobner bases with BUCHBERGER-CRITERION, do
150;; (pushnew :grobner-check *features*) and compile/load this file.
151;; With this feature, the calculations will slow down CONSIDERABLY.
152;;
153;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
154
155(defun grobner-test (ring g f)
156 "Test whether G is a Grobner basis and F is contained in G. Return T
157upon success and NIL otherwise."
158 (debug-cgb "~&GROBNER CHECK: ")
159 (let (($poly_grobner_debug nil)
160 (stat1 (buchberger-criterion ring g))
161 (stat2
162 (every #'poly-zerop
163 (makelist (normal-form ring (copy-tree (elt f i)) g nil)
164 (i 0 (1- (length f)))))))
165 (unless stat1 (error "~&Buchberger criterion failed."))
166 (unless stat2
167 (error "~&Original polys not in ideal spanned by Grobner.")))
168 (debug-cgb "~&GROBNER CHECK END")
169 t)
[66]170
171
172;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
173;;
174;; Selection of algorithm and pair heuristic
175;;
[1]176;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
177
178(defun find-grobner-function (algorithm)
179 "Return a function which calculates Grobner basis, based on its
180names. Names currently used are either Lisp symbols, Maxima symbols or
181keywords."
182 (ecase algorithm
183 ((buchberger :buchberger $buchberger) #'buchberger)
184 ((parallel-buchberger :parallel-buchberger $parallel_buchberger) #'parallel-buchberger)
185 ((gebauer-moeller :gebauer_moeller $gebauer_moeller) #'gebauer-moeller)))
186
187(defun grobner (ring f &optional (start 0) (top-reduction-only nil))
188 ;;(setf F (sort F #'< :key #'sugar))
189 (funcall
190 (find-grobner-function $poly_grobner_algorithm)
191 ring f start top-reduction-only))
192
193(defun reduced-grobner (ring f &optional (start 0) (top-reduction-only $poly_top_reduction_only))
194 (reduction ring (grobner ring f start top-reduction-only)))
195
196
197
198
199;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
200;;
201;; Conversion from internal to infix form
202;;
203;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
204
205(defun coerce-to-infix (poly-type object vars)
206 (case poly-type
207 (:termlist
208 `(+ ,@(mapcar #'(lambda (term) (coerce-to-infix :term term vars)) object)))
209 (:polynomial
210 (coerce-to-infix :termlist (poly-termlist object) vars))
211 (:poly-list
212 `([ ,@(mapcar #'(lambda (p) (coerce-to-infix :polynomial p vars)) object)))
213 (:term
214 `(* ,(term-coeff object)
215 ,@(mapcar #'(lambda (var power) `(expt ,var ,power))
216 vars (monom-exponents (term-monom object)))))
217 (otherwise
218 object)))
219
220
221;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
222;;
223;; Order utilities
224;;
225;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
226(defun find-order (order)
227 "This function returns the order function bases on its name."
228 (cond
229 ((null order) nil)
230 ((symbolp order)
231 (case order
232 ((lex :lex $lex) #'lex>)
233 ((grlex :grlex $grlex) #'grlex>)
234 ((grevlex :grevlex $grevlex) #'grevlex>)
[120]235 ((invlex :invlex $invlex) #'invlex>)
[1]236 ((elimination-order-1 :elimination-order-1 elimination_order_1) #'elimination-order-1)
[120]237 (otherwise
[1]238 (warn "~%Warning: Order ~A not found. Using default.~%" order))))
239 (t
240 (warn "~%Order specification ~A is not recognized. Using default.~%" order)
241 nil)))
242
243(defun find-ring (ring)
244 "This function returns the ring structure bases on input symbol."
245 (cond
246 ((null ring) nil)
247 ((symbolp ring)
248 (case ring
[121]249 ((expression-ring :expression-ring $expression_ring) *expression-ring*)
[1]250 ((ring-of-integers :ring-of-integers $ring_of_integers) *ring-of-integers*)
[121]251 (otherwise
[1]252 (warn "~%Warning: Ring ~A not found. Using default.~%" ring))))
253 (t
254 (warn "~%Ring specification ~A is not recognized. Using default.~%" ring)
255 nil)))
256
257(defmacro with-monomial-order ((order) &body body)
258 "Evaluate BODY with monomial order set to ORDER."
259 `(let ((*monomial-order* (or (find-order ,order) *monomial-order*)))
260 . ,body))
[127]261
[1]262(defmacro with-coefficient-ring ((ring) &body body)
263 "Evaluate BODY with coefficient ring set to RING."
264 `(let ((*coefficient-ring* (or (find-ring ,ring) *coefficient-ring*)))
265 . ,body))
266
267(defmacro with-elimination-orders ((primary secondary elimination-order)
268 &body body)
269 "Evaluate BODY with primary and secondary elimination orders set to PRIMARY and SECONDARY."
270 `(let ((*primary-elimination-order* (or (find-order ,primary) *primary-elimination-order*))
271 (*secondary-elimination-order* (or (find-order ,secondary) *secondary-elimination-order*))
272 (*elimination-order* (or (find-order ,elimination-order) *elimination-order*)))
273 . ,body))
274
275
276
277;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
278;;
279;; Conversion from internal form to Maxima general form
280;;
281;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
282
283(defun maxima-head ()
284 (if $poly_return_term_list
[17]285 '(mlist)
286 '(mplus)))
287
288(defun coerce-to-maxima (poly-type object vars)
[130]289 (case poly-type
[17]290 (:polynomial
[130]291 `(,(maxima-head) ,@(mapcar #'(lambda (term) (coerce-to-maxima :term term vars)) (poly-termlist object))))
[17]292 (:poly-list
293 `((mlist) ,@(mapcar #'(lambda (p) (funcall *ratdisrep-fun* (coerce-to-maxima :polynomial p vars))) object)))
[26]294 (:term
295 `((mtimes) ,(funcall *ratdisrep-fun* (term-coeff object))
[17]296 ,@(mapcar #'(lambda (var power) `((mexpt) ,var ,power))
297 vars (monom-exponents (term-monom object)))))
[1]298 ;; Assumes that Lisp and Maxima logicals coincide
299 (:logical object)
300 (otherwise
301 object)))
302
303
304
305;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
306;;
307;; Macro facility for writing Maxima-level wrappers for
308;; functions operating on internal representation
309;;
310;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
311
312(defmacro with-parsed-polynomials (((maxima-vars &optional (maxima-new-vars nil new-vars-supplied-p))
313 &key (polynomials nil)
314 (poly-lists nil)
315 (poly-list-lists nil)
316 (value-type nil))
317 &body body
318 &aux (vars (gensym))
319 (new-vars (gensym)))
320 `(let ((,vars (coerce-maxima-list ,maxima-vars))
321 ,@(when new-vars-supplied-p
322 (list `(,new-vars (coerce-maxima-list ,maxima-new-vars)))))
323 (coerce-to-maxima
324 ,value-type
325 (with-coefficient-ring ($poly_coefficient_ring)
326 (with-monomial-order ($poly_monomial_order)
327 (with-elimination-orders ($poly_primary_elimination_order
328 $poly_secondary_elimination_order
329 $poly_elimination_order)
330 (let ,(let ((args nil))
331 (dolist (p polynomials args)
332 (setf args (cons `(,p (parse-poly ,p ,vars)) args)))
333 (dolist (p poly-lists args)
334 (setf args (cons `(,p (parse-poly-list ,p ,vars)) args)))
335 (dolist (p poly-list-lists args)
336 (setf args (cons `(,p (parse-poly-list-list ,p ,vars)) args))))
337 . ,body))))
338 ,(if new-vars-supplied-p
339 `(append ,vars ,new-vars)
340 vars))))
341
342
Note: See TracBrowser for help on using the repository browser.