home *** CD-ROM | disk | FTP | other *** search
- ;;; -*- Mode:Lisp; Package:Weyli; Base:10; Lowercase:T; Syntax:Common-Lisp -*-
- ;;; ===========================================================================
- ;;; Coercions
- ;;; ===========================================================================
- ;;; (c) Copyright 1989, 1991 Cornell University
-
- ;;; $Id: coercions.lisp,v 2.9 1991/10/04 22:42:58 rz Exp $
-
- (in-package "WEYLI")
-
- ;; Scalars
-
- (defmethod zero ((domain domain))
- (coerce 0 domain))
-
- (defmethod one ((domain domain))
- (coerce 1 domain))
-
- (defmethod-binary max-pair domain-element (x y)
- (if (> x y) x y))
-
- (defmethod-binary min-pair domain-element (x y)
- (if (> x y) y x))
-
-
-
- ;; Since we don't have an error system in Common Lisp yet, we use the
- ;; following flag to control whether an error is generated or NIL is
- ;; returned from COERCE.
-
- (defvar *coercibility-checking* nil)
-
- (defmethod coerce ((elt domain-element) (d domain))
- (if (eql (domain-of elt) d) elt
- (unless *coercibility-checking*
- (error "Don't know how to coerce ~S to be an element of ~S" elt d))))
-
- ;; This root method is here so we can always use :around methods with coerce.
- (defmethod coerce (elt (d domain))
- (unless *coercibility-checking*
- (error "Don't know how to coerce ~S to be an element of ~S" elt d)))
-
- (defmethod coercible? (elt (d domain))
- (let ((*coercibility-checking* t))
- (coerce elt d)))
-
- (defmethod coerce ((value number) (domain lisp-numbers))
- value)
-
- (defmethod coerce ((value integer) (domain rational-integers))
- (make-element domain value))
-
- (defmethod coerce ((value integer) (domain GFp))
- (make-element domain value))
-
- (defmethod coerce ((value integer) (domain GFm))
- (make-element domain value 0))
-
- (defmethod coerce ((value ratio) (domain GFp))
- (make-element domain (lisp:* (lisp:numerator value)
- (compute-inverse (lisp:denominator value)
- (characteristic domain)))))
-
- (defmethod coerce ((elt GFp-element) (domain GFm))
- (with-slots (value d1) elt
- (make-element domain value (characteristic d1))))
-
- ;; Real number coercions
- (defmethod coerce ((number bigfloat) (domain real-numbers))
- number)
-
- ;; This function converts an integer intgr to a BigFloat.
- (defmethod coerce ((int integer) (domain real-numbers))
- (make-bigfloat domain int 0))
-
- (defmethod coerce ((number float) (domain real-numbers))
- (bind-domain-context domain
- (read!num (format nil "~E" number))))
-
- (defmethod coerce ((r ratio) (domain real-numbers))
- (/ (make-bigfloat domain (lisp::numerator r) 0)
- (make-bigfloat domain (lisp::denominator r) 0)))
-
- (defmethod coerce ((number float) (domain floating-point-numbers))
- number)
-
- (defmethod coerce ((number quotient-element) (domain floating-point-numbers))
- (let ((num (coerce (numerator number) domain))
- (den (coerce (denominator number) domain)))
- (if (or (null num) (null den))
- (unless *coercibility-checking*
- (error "Can't coerce ~S into ~D" number domain))
- (/ num den))))
-
- (defmethod coerce ((int integer) (domain floating-point-numbers))
- (float int 1.0d0))
-
- (defmethod coerce ((number string) (domain real-numbers))
- (read!num number))
-
- (defmethod coerce ((number bigfloat) (domain rational-integers))
- (with-slots (mantissa exponent) (cut!ep number 0)
- (if (0? exponent) mantissa
- (lisp:* mantissa (lisp:expt 10 exponent)))))
-
-
- ;; Modules We assume that Lisp numbers can always be coerced into
- ;; modules. The generic function embed-coefficient* is used to embed a
- ;; domain-element into the the coefficient domain of a module. The *
- ;; indicates that it doesn't bother checking to see if the elt is
- ;; actually an element of the coefficient. embed-coefficient does the checking.
-
- (defmacro define-module-coercions (&rest types)
- `(progn
- ,@(loop for type in types
- collect
- `(defmethod coerce :around ((number ,type) (domain module))
- (let* ((coefficient-domain (coefficient-domain domain))
- coef)
- (if (and coefficient-domain
- (setq coef (coercible? number coefficient-domain)))
- (embed-coefficient* coef domain)
- (call-next-method number domain)))))))
-
- (define-module-coercions integer float ratio rational-number)
-
- (defmethod embed-coefficient (elt (domain module))
- (if (eql (domain-of elt) (coefficient-domain domain))
- (embed-coefficient* elt domain)
- (error "~S is not an element of the coefficient domain of ~S"
- elt domain)))
-
- ;; Derivatives
-
- (defmethod coerce ((variable list) (domain differential-polynomial-ring))
- (cond ((member variable (ring-variables domain))
- (make-polynomial domain
- (cons (variable-index domain variable)
- (make-terms 1 (one (coefficient-domain domain))))))
- ((and (not (atom variable))
- (eql (first variable) 'deriv))
- (loop for i below (third variable)
- for p = (deriv (coerce (second variable) domain)) then (deriv p)
- finally (return p)))
- ((coercible? variable (coefficient-domain domain)))
- (t (call-next-method variable domain))))
-
- ;; Quotient fields
-
- (defmethod coerce ((int integer) (qf quotient-field))
- (make-instance 'rational-function :domain qf
- :numerator (coerce int (QF-ring qf))
- :denominator (coerce 1 (QF-ring qf))))
-
- ;; Rational numbers
-
- (defmethod coerce ((int integer) (Q rational-numbers))
- (make-instance 'rational-number :domain q :numerator int :denominator 1))
-
- (defmethod coerce ((r ratio) (Q rational-numbers))
- (make-instance 'rational-number :domain q
- :numerator (lisp:numerator r)
- :denominator (lisp:denominator r)))
-
-
- ;; This code provides primary methods for those situations when all
- ;; applicable methods are :around methods.
-
- (defvar *coerce-where-possible* nil)
-
- (defmacro def-binary-coercion (op illegal-mess ambig-mess)
- `(defmethod ,op (x y)
- (when (null *coerce-where-possible*)
- (error ,illegal-mess x y))
- (let ((domain-x (domain-of x))
- (domain-y (domain-of y))
- temp-x temp-y)
- (when (eql domain-x domain-y)
- (error ,illegal-mess x y))
- (setq temp-x (coercible? x domain-y))
- (setq temp-y (coercible? y domain-x))
- (cond ((and temp-x temp-y)
- (error ,ambig-mess x y))
- (temp-x
- (,op temp-x y))
- (temp-y
- (,op x temp-y))
- (t
- (error ,illegal-mess x y))))))
-
- (def-binary-coercion plus
- "No way to add ~S and ~S"
- "Ambiguous coercion for addition ( ~S, ~S)")
-
- (def-binary-coercion difference
- "No way to subtract ~S and ~S"
- "Ambiguous coercion for subtraction ( ~S, ~S)")
-
- (def-binary-coercion times
- "No way to multiply ~S and ~S"
- "Ambiguous coercion for multiplication ( ~S, ~S)")
-
- (def-binary-coercion quotient
- "No way to compute the quotient of ~S and ~S"
- "Ambiguous coercion for division ( ~S, ~S)")
-
- ;; There is always a canonical map of the integers into any domain. The
- ;; following methods indicate that we should use that map for the common
- ;; operations.
-
- (defmethod plus ((x integer) y)
- (let ((xx (coerce x (domain-of y))))
- (if (eql xx x)
- (error "Infinite recursion in PLUS ~S ~S" x y)
- (plus xx y))))
-
- (defmethod plus (x (y integer))
- (let ((yy (coerce y (domain-of x))))
- (if (eql yy y)
- (error "Infinite recursion in PLUS ~S ~S" x y)
- (plus x yy))))
-
- (defmethod difference ((x integer) y)
- (let ((xx (coerce x (domain-of y))))
- (if (eql xx x)
- (error "Infinite recursion in DIFFERENCE ~S ~S" x y)
- (difference xx y))))
-
- (defmethod difference (x (y integer))
- (let ((yy (coerce y (domain-of x))))
- (if (eql yy y)
- (error "Infinite recursion in DIFFERENCE ~S ~S" x y)
- (difference x yy))))
-
- (defmethod times ((x integer) y)
- (let ((xx (coerce x (domain-of y))))
- (if (eql xx x)
- (error "Infinite recursion in TIMES ~S ~S" x y)
- (times xx y))))
-
- (defmethod times (x (y integer))
- (let ((yy (coerce y (domain-of x))))
- (if (eql yy y)
- (error "Infinite recursion in TIMES ~S ~S" x y)
- (times x yy))))
-
- (defmethod quotient ((x integer) y)
- (let ((xx (coerce x (domain-of y))))
- (if (eql xx x)
- (error "Infinite recursion in QUOTIENT ~S ~S" x y)
- (quotient xx y))))
-
- (defmethod quotient (x (y integer))
- (let ((yy (coerce y (domain-of x))))
- (if (eql yy y)
- (error "Infinite recursion in QUOTIENT ~S ~S" x y)
- (quotient x yy))))
-