;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; The data in this file contains enhancments. ;;;;; ;;; ;;;;; ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;; ;;; All rights reserved ;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; (c) Copyright 1980 Massachusetts Institute of Technology ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (in-package "MAXIMA") (macsyma-module specfn) ;********************************************************************* ;**************** ****************** ;**************** Macsyma Special Function Routines ****************** ;**************** ****************** ;********************************************************************* (load-macsyma-macros rzmac) (load-macsyma-macros mhayat) (defmacro mnumericalp (arg) `(or (floatp ,arg) (and (or $numer $float) (integerp ,arg)))) (comment Subtitle Polylogarithm Routines) (declare-top(splitfile plylog)) (declare-top(special $zerobern ivars key-vars tlist) (notype (li2numer flonum) (li3numer flonum))) (defun lisimp (exp vestigial z) vestigial ;; Ignored (let ((s (simpcheck (car (subfunsubs exp)) z)) ($zerobern t) (a)) (subargcheck exp 1 1 '$li) (setq a (simpcheck (car (subfunargs exp)) z)) (or (cond ((zerop1 a) 0) ((not (integerp s)) ()) ((= s 1) (m- `((%log) ,(m- 1 a)))) ((and (integerp a) (> s 1) (cond ((= a 1) ($zeta s)) ((= a -1) (m*t (m1- `((rat) 1 ,(expt 2 (f- s 1)))) ($zeta s)))))) ((= s 2) (li2simp a)) ((= s 3) (li3simp a))) (eqtest (subfunmakes '$li (ncons s) (ncons a)) exp)))) (defun li2simp (arg) (cond ((mnumericalp arg) (li2numer (float arg))) ((alike1 arg '((rat) 1 2)) (m+t (m// ($zeta 2) 2) (m*t '((rat simp) -1 2) (m^ '((%log) 2) 2)))))) (defun li3simp (arg) (cond ((mnumericalp arg) (li3numer (float arg))) ((alike1 arg '((rat) 1 2)) (m+t (m* '((rat simp) 7 8) '(($zeta) 3)) (m*t (m// ($zeta 2) -2) (simplify '((%log) 2))) (m*t '((rat simp) 1 6) (m^ '((%log) 2) 3)))))) (declare-top (flonum x)) ;; Numerical evaluation for Chebyschev expansions of the first kind (defun cheby (x chebarr) (declare (flonum x)) (let ((Bn+2 0.0) (Bn+1 0.0)) (declare (flonum Bn+1 Bn+2)) (do ((i (fix (arraycall flonum chebarr 0)) (f1- i))) ((< i 1) (-$ Bn+1 (*$ Bn+2 x))) (setq Bn+2 (prog1 Bn+1 (setq Bn+1 (+$ (arraycall flonum chebarr i) (-$ (*$ 2.0 x Bn+1) Bn+2)))))))) (defun cheby-prime (x chebarr) (declare (flonum x)) (-$ (cheby x chebarr) (*$ (arraycall flonum chebarr 1) .5))) ;; These should really be calculated with minimax rational approximations. ;; Someone has done LI[2] already, and this should be updated; I haven't ;; seen any results for LI[3] yet. (defun li2numer (x) (cond ((= x 0.0) 0.0) ((= x 1.0) 1.64493407) ((= x -1.0) -.822467033) ((< x -1.0) (-$ (+$ (chebyli2 (//$ x)) 1.64493407 (//$ (expt (log (-$ x)) 2) 2.0)))) ((not (> x .5)) (chebyli2 x)) ((< x 1.0) (-$ 1.64493407 (*$ (log x) (log (-$ 1.0 x))) (chebyli2 (-$ 1.0 x)))) (t (m+t (-$ 3.28986813 (//$ (expt (log x) 2) 2.0) (li2numer (//$ x))) (m*t (-$ (*$ 3.14159265 (log x))) '$%i))))) (defun li3numer (x) (cond ((= x 0.0) 0.0) ((= x 1.0) 1.20205690) ((< x -1.0) (-$ (chebyli3 (//$ x)) (*$ 1.64493407 (log (-$ x))) (//$ (expt (log (-$ x)) 3) 6.0))) ((not (> x .5)) (chebyli3 x)) ((not (> x 2.0)) (let ((fac (*$ (expt (log x) 2) .5))) (m+t (+$ 1.20205690 (-$ (*$ (log x) (-$ 1.64493407 (chebyli2 (-$ 1.0 x)))) (chebyS12 (-$ 1.0 x)) (*$ fac (log (cond ((< x 1.0) (-$ 1.0 x)) ((1-$ x))))))) (cond ((< x 1.0) 0) ((m*t (*$ fac -3.14159265) '$%i)))))) (t (m+t (+$ (chebyli3 (//$ x)) (*$ 3.28986813 (log x)) (//$ (expt (log x) 3) -6.0)) (m*t (*$ -1.57079633 (expt (log x) 2)) '$%i))))) ;(array *li2* flonum 15.) ;(array *li3* flonum 15.) ;(array *S12* flonum 18.) (defvar *li2* (*array nil 'flonum 15.)) (eval-when (load eval) (fillarray *li2* '(14.0 1.93506430 .166073033 2.48793229e-2 4.68636196e-3 1.0016275e-3 2.32002196e-4 5.68178227e-5 1.44963006e-5 3.81632946e-6 1.02990426e-6 2.83575385e-7 7.9387055e-8 2.2536705e-8 6.474338e-9)) ) (defvar *li3* (*array nil 'flonum 15.)) (eval-when (load eval) (fillarray *li3* '(14.0 1.95841721 8.51881315e-2 8.55985222e-3 1.21177214e-3 2.07227685e-4 3.99695869e-5 8.38064066e-6 1.86848945e-6 4.36660867e-7 1.05917334e-7 2.6478920e-8 6.787e-9 1.776536e-9 4.73417e-10)) ) (defvar *s12* (*array nil 'flonum 18.)) (eval-when (load eval) (fillarray *S12* '(17.0 1.90361778 .431311318 .100022507 2.44241560e-2 6.22512464e-3 1.64078831e-3 4.44079203e-4 1.22774942e-4 3.45398128e-5 9.85869565e-6 2.84856995e-6 8.31708473e-7 2.45039499e-7 7.2764962e-8 2.1758023e-8 6.546158e-9 1.980328e-9)) ) (defun chebyli2 (x) (*$ x (cheby-prime (//$ (1+$ (*$ x 4.0)) 3.0) *li2*))) ; #+Maclisp '#,(get '*li2* 'array) ; #+Franz (getd '*li2*) ; #-(Or Maclisp Franz) (get-array-pointer '*li2*)))) (defun chebyli3 (x) (*$ x (cheby-prime (//$ (1+$ (*$ 4.0 x)) 3.0) *li3*))) ; #+Maclisp '#,(get '*li3* 'array) ; #+Franz (getd '*li3*) ; #-(or Maclisp Franz) (get-array-pointer '*li3*)))) (defun chebyS12 (x) (*$ (//$ (expt x 2) 4.0) (cheby-prime (//$ (1+$ (*$ 4.0 x)) 3.0) *s12*))) ; #+Maclisp '#,(get '*S12* 'array) ; #+Franz (getd '*S12*) ; #-(or Maclisp Franz) (get-array-pointer '*S12*)))) (declare-top(notype x)) (comment Subtitle Polygamma Routines) (declare-top(splitfile plygam)) ;; gross efficiency hack, exp is a function of *k*, *k* should be mbind'ed (defun msum (exp lo hi) (if (< hi lo) 0 (let ((sum 0)) (do ((*k* lo (f1+ *k*))) ((> *k* hi) sum) (declare (special *k*)) (setq sum (add2 sum (meval exp))))))) (defun pole-err (exp) (declare (special errorsw)) (cond (errorsw (throw 'errorsw t)) (t (merror "Pole encountered in: ~M" exp) ))) (declare-top (special $maxpsiposint $maxpsinegint $maxpsifracnum $maxpsifracdenom) (fixnum $maxpsiposint $maxpsinegint $maxpsifracnum $maxpsifracdenom) (*lexpr $diff)) (defprop $psi psisimp specsimp) (mapcar (function (lambda (var val) (and (not (boundp var)) (set var val)))) '($maxpsiposint $maxpsinegint $maxpsifracnum $maxpsifracdenom) '(20. -10. 4 4)) (defun psisimp (exp a z) (let ((s (simpcheck (car (subfunsubs exp)) z))) (subargcheck exp 1 1 '$psi) (setq a (simpcheck (car (subfunargs exp)) z)) (and (integerp a) (< a 1) (pole-err exp)) (eqtest (psisimp1 s a) exp))) ;; This gets pretty hairy now. (defun psisimp1 (s a) (let ((*k*)) (declare (special *k*)) (or (and (not $numer) (not $float) (integerp s) (> s -1) (cond ((integerp a) (and (not (> a $maxpsiposint)) ; integer values (m*t (expt -1 s) (factorial s) (m- (msum (inv (m^t '*k* (f1+ s))) 1 (f1- a)) (cond ((zerop s) '$%gamma) (($zeta (f1+ s)))))))) ((or (not (ratnump a)) (ratgreaterp a $maxpsiposint)) ()) ((ratgreaterp a 0) (cond ((ratgreaterp a 1) (let* ((int ($entier a)) ; reduction to fractional values (frac (m-t a int))) (m+t (psisimp1 s frac) (if (> int $maxpsiposint) (subfunmakes '$psi (ncons s) (ncons int)) (m*t (expt -1 s) (factorial s) (msum (m^t (m+t (m-t a int) '*k*) (f1- (f- s))) 0 (f1- int))))))) ((= s 0) (let ((p (cadr a)) (q (caddr a))) (cond ((or (greaterp p $maxpsifracnum) (greaterp q $maxpsifracdenom) (bigp p) (bigp q)) ()) ((and (= p 1) (cond ((= q 2) (m+ (m* -2 '((%log) 2)) (m- '$%gamma))) ((= q 3) (m+ (m* '((rat simp) -1 2) (m^t 3 '((rat simp) -1 2)) '$%pi) (m* '((rat simp) -3 2) '((%log) 3)) (m- '$%gamma))) ((= q 4) (m+ (m* '((rat simp) -1 2) '$%pi) (m* -3 '((%log) 2)) (m- '$%gamma)))))) ((and (= p 2) (= q 3)) (m+ (m* '((rat simp) 1 2) (m^t 3 '((rat simp) -1 2)) '$%pi) (m* '((rat simp) -3 2) '((%log) 3)) (m- '$%gamma))) ((and (= p 3) (= q 4)) (m+ (m* '((rat simp) 1 2) '$%pi) (m* -3 '((%log) 2)) (m- '$%gamma))) ;; Gauss's Formula ((let ((f (m* `((%cos) ,(m* 2 a '$%pi '*k*)) `((%log) ,(m-t 2 (m* 2 `((%cos) ,(m//t (m* 2 '$%pi '*k*) q)))))))) (m+t (msum f 1 (f1- (// q 2))) (let ((*k* (// q 2))) (declare (special *k*)) (m*t (meval f) (cond ((oddp q) 1) ('((rat simp) 1 2))))) (m-t (m+ (m* '$%pi '((rat simp) 1 2) `((%cot) ((mtimes simp) ,a $%pi))) `((%log) ,q) '$%gamma)))))))) ((alike1 a '((rat) 1 2)) (m*t (expt -1 (f1+ s)) (factorial s) (f1- (expt 2 (f1+ s))) (simplify ($zeta (f1+ s))))))) ((ratgreaterp a $maxpsinegint) ;;; Reflection Formula (m*t (^ -1 s) (m+t (m+t (psisimp1 s (m- a)) (let ((dif ($diff `((%cot) ,(m* '$%pi '$z)) '$z s)) ($z (m-t a))) (declare (special $z)) (meval dif))) (m*t (factorial s) (m^t (m-t a) (f1- (f- s))))))))) (subfunmakes '$psi (ncons s) (ncons a))))) (comment Subtitle Polygamma Tayloring Routines) ;; These routines are specially coded to be as fast as possible given the ;; current $TAYLOR; too bad they have to be so ugly. (declare-top(special var subl last sign last-exp)) (defun expgam-fun (pw temp) (setq temp (get-datum (get-key-var (car var)))) (let-pw temp pw (pstimes (let-pw temp (e1+ pw) (psexpt-fn (getexp-fun '(($PSI) -1) var (e1+ pw)))) (make-ps var (ncons pw) '(((-1 . 1) 1 . 1)))))) (defun expplygam-funs (pw subl l) ; l is a irrelevant here (setq subl (car subl)) (if (or (not (integerp subl)) (lessp subl -1)) (tay-err "Unable to expand at a subscript in") (prog ((e 0) (sign 0) npw) (declare (flonum npw) (fixnum e) #-Multics (fixnum sign)) (setq npw (//$ (float (car pw)) (float (cdr pw)))) (setq l (cond ((= subl -1) `(((1 . 1) . ,(prep1 '((mtimes) -1 $%gamma))))) ((= subl 0) (cons '((-1 . 1) -1 . 1) (if (> 0.0 npw) () `(((0 . 1) . ,(prep1 '((mtimes) -1 $%gamma))))))) (T (setq last (factorial subl)) `(((,(f- (f1+ subl)) . 1) ,(times (^ -1 (f1+ subl)) (factorial subl)) . 1)))) e (if (< subl 1) (f- subl) -1) sign (if (< subl 1) -1 (^ -1 subl))) a (setq e (f1+ e) sign (f- sign)) (if (greaterp e npw) (return l) (rplacd (last l) `(((,e . 1) . ,(rctimes (rcplygam e) (prep1 ($zeta (f+ (f1+ subl) e)))))))) (go a)))) (defun rcplygam (k) (declare (fixnum k) ) (cond ((= subl -1) (cons sign k)) ((= subl 0) (cons sign 1)) (t (prog1 (cons (times sign last) 1) (setq last (*quo (times last (plus subl (add1 k))) (add1 k))))))) (defun plygam-ord (subl) (if (equal (car subl) -1) (ncons (rcone)) `((,(f- (f1+ (car subl))) . 1)))) (defun plygam-pole (a c func) (if (rcmintegerp c) (let ((ps (get-lexp (m- a (rcdisrep c)) () t))) (rplacd (cddr ps) (cons `((0 . 1) . ,c) (cdddr ps))) (if (atom func) (gam-const a ps func) (plygam-const a ps func))) (prep1 (simplifya (if (atom func) `((%GAMMA) ,(rcdisrep c)) `((MQAPPLY) ,func ,(rcdisrep c))) () )))) (defun gam-const (a arg func) (let ((const (ps-lc* arg)) (arg-c)) (ifn (rcintegerp const) (taylor2 (diff-expand `((%GAMMA) ,a) tlist)) (setq const (car const)) ;; Try to get the datum (if (pscoefp arg) (setq arg-c (get-lexp (m+t a (minus const)) (rcone) (signp le const)))) (if (and arg-c (not (psp arg-c))) ; must be zero (taylor2 (simplify `((%GAMMA) ,const))) (let ((datum (get-datum (get-key-var (gvar (or arg-c arg))))) (ord (if arg-c (le (terms arg-c)) (le (n-term (terms arg)))))) (setq func (current-trunc datum)) (if (greaterp const 0) (pstimes (let-pw datum (e- func ord) (expand (m+t a (minus const)) '%GAMMA)) (let-pw datum (e+ func ord) (tsprsum (m+t a (m-t '%%taylor-index%%)) `(%%taylor-index%% 1 ,const) '%PRODUCT))) (pstimes (expand (m+t a (minus const)) '%GAMMA) (let-pw datum (e+ func ord) (psexpt (tsprsum (m+t a '%%taylor-index%%) `(%%taylor-index%% 0 ,(minus (add1 const))) '%PRODUCT) (rcmone)))))))))) (defun plygam-const (a arg func) (let ((const (ps-lc* arg)) (sub (cadr func))) (cond ((or (not (integerp sub)) (< sub -1)) (tay-err "Unable to expand at a subscript in")) ((not (rcintegerp const)) (taylor2 (diff-expand `((MQAPPLY) ,func ,a) tlist))) (T (setq const (car const)) (psplus (expand (m+t a (f- const)) func) (if (> const 0) (pstimes (cons (times (^ -1 sub) (factorial sub)) 1) (tsprsum `((MEXPT) ,(m+t a (m-t '%%taylor-index%%)) ,(f- (f1+ sub))) `(%%taylor-index%% 1 ,const) '%SUM)) (pstimes (cons (times (^ -1 (f1+ sub)) (factorial sub)) 1) (tsprsum `((MEXPT) ,(m+t a '%%taylor-index%%) ,(f- (f1+ sub))) `(%%taylor-index%% 0 ,(f- (f1+ const))) '%SUM)))))))) (declare-top(unspecial var subl last sign last-exp)) ;; Not done correctly ;; ;; (defun beta-trans (argl funname) ;; funname ;ignored ;; (let ((sum (m+t (car argl) (cadr argl))) (PSI[-1] '(($PSI ARRAY) -1))) ;; (if (zerop sum) (unfam-sing-err) ;; (taylor2 `((MTIMES) ;; ((MEXPT) $%E ((MPLUS) ((MQAPPLY) ,PSI[-1] ,(car argl)) ;; ((MQAPPLY) ,PSI[-1] ,(cadr argl)) ;; ((MTIMES) -1 ;; ((MQAPPLY) ,PSI[-1] ,sum)))) ;; ((MPLUS) ((MEXPT) ,(car argl) -1) ;; ((MEXPT) ,(cadr argl) -1)))))))