;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; Copyright (C) 1999, 2002, 2009, 2015 Marek Rychlik ;;; ;;; This program is free software; you can redistribute it and/or modify ;;; it under the terms of the GNU General Public License as published by ;;; the Free Software Foundation; either version 2 of the License, or ;;; (at your option) any later version. ;;; ;;; This program is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;;; GNU General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program; if not, write to the Free Software ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;---------------------------------------------------------------- ;; This package implements BASIC OPERATIONS ON MONOMIALS ;;---------------------------------------------------------------- ;; DATA STRUCTURES: Conceptually, monomials can be represented as lists: ;; ;; monom: (n1 n2 ... nk) where ni are non-negative integers ;; ;; However, lists may be implemented as other sequence types, ;; so the flexibility to change the representation should be ;; maintained in the code to use general operations on sequences ;; whenever possible. The optimization for the actual representation ;; should be left to declarations and the compiler. ;;---------------------------------------------------------------- ;; EXAMPLES: Suppose that variables are x and y. Then ;; ;; Monom x*y^2 ---> (1 2) ;; ;;---------------------------------------------------------------- (defpackage "MONOMIAL" (:use :cl) (:export "MONOM" "EXPONENT" "MAKE-MONOM" "MONOM-ELT" "MONOM-DIMENSION" "MONOM-TOTAL-DEGREE" "MONOM-SUGAR" "MONOM-DIV" "MONOM-MUL" "MONOM-DIVIDES-P" "MONOM-DIVIDES-MONOM-LCM-P" "MONOM-LCM-DIVIDES-MONOM-LCM-P" "MONOM-LCM-EQUAL-MONOM-LCM-P" "MONOM-DIVISIBLE-BY-P" "MONOM-REL-PRIME-P" "MONOM-EQUAL-P" "MONOM-LCM" "MONOM-GCD" "MONOM-DEPENDS-P" "MONOM-MAP" "MONOM-APPEND" "MONOM-CONTRACT" "MONOM-EXPONENTS")) (in-package :monomial) (deftype exponent () "Type of exponent in a monomial." 'fixnum) (defstruct (monom ;; BOA constructor (:constructor make-monom (dimension &key (initial-contents #() initial-contents-supplied-p) (initial-element #() initial-element-supplied-p) (exponents (cond (initial-contents-supplied-p (make-array (list dimension) :initial-contents initial-contents :element-type 'exponent)) (initial-element-supplied-p (make-array (list dimension) :initial-element initial-element :element-type 'exponent)) (t (make-array (list dimension) :element-type 'exponent :initial-element 0))))))) (exponents nil :type (vector exponent *))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Operations on monomials ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun monom-dimension (m) (declare (type monom m)) (length (monom-exponents m))) (defmacro monom-elt (m index) "Return the power in the monomial M of variable number INDEX." `(elt (monom-exponents ,m) ,index)) (defun monom-total-degree (m &optional (start 0) (end (monom-dimension m))) "Return the todal degree of a monomoal M. Optinally, a range of variables may be specified with arguments START and END." (declare (type monom m) (fixnum start end)) (reduce #'+ (monom-exponents m) :start start :end end)) (defun monom-sugar (m &aux (start 0) (end (monom-dimension m))) "Return the sugar of a monomial M. Optinally, a range of variables may be specified with arguments START and END." (declare (type monom m) (fixnum start end)) (monom-total-degree m start end)) (defun monom-div (m1 m2 &aux (result (copy-structure m1))) "Divide monomial M1 by monomial M2." (declare (type monom m1 m2)) (map-into (monom-exponents result) #'- (monom-exponents m1) (monom-exponents m2)) result) (defun monom-mul (m1 m2 &aux (result (copy-structure m1))) "Multiply monomial M1 by monomial M2." (declare (type monom m1 m2 result)) (map-into (monom-exponents result) #'+ (monom-exponents m1) (monom-exponents m2)) result) (defun monom-divides-p (m1 m2) "Returns T if monomial M1 divides monomial M2, NIL otherwise." (declare (type monom m1 m2)) (every #'<= (monom-exponents m1) (monom-exponents m2))) (defun monom-divides-monom-lcm-p (m1 m2 m3) "Returns T if monomial M1 divides MONOM-LCM(M2,M3), NIL otherwise." (declare (type monom m1 m2 m3)) (every #'(lambda (x y z) (declare (type exponent x y z)) (<= x (max y z))) (monom-exponents m1) (monom-exponents m2) (monom-exponents m3))) (defun monom-lcm-divides-monom-lcm-p (m1 m2 m3 m4) "Returns T if monomial MONOM-LCM(M1,M2) divides MONOM-LCM(M3,M4), NIL otherwise." (declare (type monom m1 m2 m3 m4)) (every #'(lambda (x y z w) (declare (type exponent x y z w)) (<= (max x y) (max z w))) (monom-exponents m1) (monom-exponents m2) (monom-exponents m3) (monom-exponents m4))) (defun monom-lcm-equal-monom-lcm-p (m1 m2 m3 m4) "Returns T if monomial MONOM-LCM(M1,M2) equals MONOM-LCM(M3,M4), NIL otherwise." (declare (type monom m1 m2 m3 m4)) (every #'(lambda (x y z w) (declare (type exponent x y z w)) (= (max x y) (max z w))) (monom-exponents m1) (monom-exponents m2) (monom-exponents m3) (monom-exponents m4))) (defun monom-divisible-by-p (m1 m2) "Returns T if monomial M1 is divisible by monomial M2, NIL otherwise." (declare (type monom m1 m2)) (every #'>= (monom-exponents m1) (monom-exponents m2))) (defun monom-rel-prime-p (m1 m2) "Returns T if two monomials M1 and M2 are relatively prime (disjoint)." (declare (type monom m1 m2)) (every #'(lambda (x y) (declare (type exponent x y)) (zerop (min x y))) (monom-exponents m1) (monom-exponents m2))) (defun monom-equal-p (m1 m2) "Returns T if two monomials M1 and M2 are equal." (declare (type monom m1 m2)) (every #'= (monom-exponents m1) (monom-exponents m2))) (defun monom-lcm (m1 m2 &aux (result (copy-structure m1))) "Returns least common multiple of monomials M1 and M2." (declare (type monom m1 m2)) (map-into (monom-exponents result) #'max (monom-exponents m1) (monom-exponents m2)) result) (defun monom-gcd (m1 m2 &aux (result (copy-structure m1))) "Returns greatest common divisor of monomials M1 and M2." (declare (type monom m1 m2)) (map-into (monom-exponents result) #'min (monom-exponents m1) (monom-exponents m2)) result) (defun monom-depends-p (m k) "Return T if the monomial M depends on variable number K." (declare (type monom m) (fixnum k)) (plusp (monom-elt m k))) (defmacro monom-map (fun m &rest ml &aux (result `(copy-structure ,m))) `(map-into (monom-exponents ,result) ,fun ,m ,@ml)) (defmacro monom-append (m1 m2) `(make-monom (list (+ (monom-dimension ,m1) (monom-dimension ,m2))) :initial-contents (concatenate 'monom (monom-exponents ,m1) (monom-exponents ,m2)))) (defmacro monom-contract (k m) `(setf (monom-exponents ,m) (subseq (monom-exponents ,m) ,k)))