Fix bug #3926: Various limits give UND where they should give IND
[maxima.git] / src / specfn.lisp
blobab9b22853173fbe6bc5ab6f9bf94edbcb723e09f
1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancments. ;;;;;
4 ;;; ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; (c) Copyright 1980 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11 (in-package :maxima)
13 (macsyma-module specfn)
15 ;;*********************************************************************
16 ;;**************** ******************
17 ;;**************** Macsyma Special Function Routines ******************
18 ;;**************** ******************
19 ;;*********************************************************************
21 (load-macsyma-macros rzmac)
22 (load-macsyma-macros mhayat)
24 (defmacro mnumericalp (arg)
25 `(or (floatp ,arg) (and (or $numer $float) (integerp ,arg))))
27 ;; subtitle polylogarithm routines
29 (declare-top (special $zerobern tlist %e-val))
31 (defun lisimp (expr vestigial z)
32 (declare (ignore vestigial))
33 (let ((s (simpcheck (car (subfunsubs expr)) z))
34 ($zerobern t)
35 (a))
36 (subargcheck expr 1 1 '$li)
37 (setq a (simpcheck (car (subfunargs expr)) z))
38 (or (cond ((zerop1 a) a)
39 ((and (mnump s) (ratgreaterp s 1) (eql a 1))
40 ;; li[s](a) = zeta(s) if s > 1 and if a = 1. We
41 ;; simplify this only if s is a rational number and a
42 ;; is the integer 1.
43 (ftake '%zeta s))
44 ((not (integerp s)) ())
45 ((= s 1)
46 (if (onep1 a)
47 (simp-domain-error
48 (intl:gettext "li: li[~:M](~:M) is undefined.") s a)
49 (neg (take '(%log) (sub 1 a)))))
50 ((= s 0) (div a (sub 1 a)))
51 ((< s 0) (lisimp-negative-integer s a))
52 ((and (integerp a) (> s 1)
53 (cond ((= a 1) (take '(%zeta) s))
54 ((= a -1)
55 ;; li[s](-1) = (2^(1-s)-1)*zeta(s)
56 (mul (add -1 (inv (expt 2 (- s 1))))
57 (take '(%zeta) s))))))
58 ((= s 2) (li2simp a))
59 ((= s 3) (li3simp a))
60 ((or (complex-float-numerical-eval-p a)
61 (complex-bigfloat-numerical-eval-p a))
62 (cond ((bigfloat:= 1 (bigfloat:to a))
63 ;; li[s](1) -> zeta(s)
64 (let ((result ($zeta s)))
65 (if (floatp a)
66 ($float result)
67 ($bfloat result))))
68 ((bigfloat:= -1 (bigfloat:to a))
69 ;; li[s](-1) = (2^(1-s)-1)*zeta(s)
70 (let ((result (mul (add -1 (inv (expt 2 (- s 1))))
71 (take '(%zeta) s))))
72 (if (floatp a)
73 ($float result)
74 ($bfloat result))))
75 ((integerp s)
76 (to (bigfloat::li-s-simp s (bigfloat:to a)))))))
77 (eqtest (subfunmakes '$li (ncons s) (ncons a))
78 expr))))
80 ;; Expand the Polylogarithm li[s](z) for a negative integer parameter s.
81 (defun lisimp-negative-integer (s z)
82 (let ((n (- s)))
83 (mul (inv (power (sub 1 z) (+ n 1)))
84 (let ((index1 (gensumindex))
85 ($simpsum t))
86 (dosum
87 (mul (power z index1)
88 (let ((index2 (gensumindex)))
89 (dosum
90 (mul (power -1 (add index2 1))
91 (take '(%binomial) (+ n 1) (sub index2 1))
92 (power (add 1 (sub index1 index2)) n))
93 index2 1 index1 t)))
94 index1 1 n t)))))
96 (defun li2simp (arg)
97 (cond ((mnumericalp arg)
98 ;; When arg is a float or rational, use the original li2numer
99 ;; using Spences function.
100 (li2numer (float arg)))
101 ((complex-float-numerical-eval-p arg)
102 ;; For complex args that should should result in float
103 ;; answers, use bigfloat::li2numer.
104 (to (bigfloat::li2numer (bigfloat:to ($rectform ($float arg))))))
105 ((or (bigfloat-numerical-eval-p arg)
106 (complex-bigfloat-numerical-eval-p arg))
107 (to (bigfloat::li2numer (bigfloat:to ($rectform ($bfloat arg))))))
108 ((alike1 arg '((rat) 1 2))
109 (add (div (take '(%zeta) 2) 2)
110 (mul '((rat simp) -1 2)
111 (power (take '(%log) 2) 2))))))
113 (defun li3simp (arg)
114 (cond ((or (float-numerical-eval-p arg)
115 (complex-float-numerical-eval-p arg))
116 (to (bigfloat::li3numer (bigfloat:to ($rectform ($float arg))))))
117 ((or (bigfloat-numerical-eval-p arg)
118 (complex-bigfloat-numerical-eval-p arg))
119 (to (bigfloat::li3numer (bigfloat:to ($rectform ($bfloat arg))))))
120 ((alike1 arg '((rat) 1 2))
121 (add (mul '((rat simp) 7 8) (take '(%zeta) 3))
122 (mul (div (take '(%zeta) 2) -2) (take '(%log) 2))
123 (mul '((rat simp) 1 6) (power (take '(%log) 2) 3))))))
125 ;; exponent in first term of taylor expansion of $li is one
126 (defun li-ord (subl)
127 (declare (ignore subl))
128 (ncons (rcone)))
130 ;; taylor expansion of $li is its definition:
131 ;; x + x^2/2^s + x^3/3^s + ...
132 (defun exp$li-fun (pw subl l) ; l is a irrelevant here
133 (setq subl (car subl)) ; subl is subscript of li
134 (prog ((e 0) ; e is exponent of current term
135 npw) ; npw is exponent of last term needed
136 (declare (fixnum e))
137 (setq npw (/ (float (car pw)) (float (cdr pw))))
138 (setq
139 l (cons '((0 . 1) 0 . 1)
140 nil))
141 a (setq e (1+ e))
142 (if (> e npw) (return l)
143 (rplacd (last l)
144 `(((,e . 1)
145 . ,(prep1 (m^ e (m- subl)))))))
146 (go a)))
149 ;; computes first pw terms of asymptotic expansion of $li[s](z)
151 ;; pw should be < (1/2)*s or gamma term is undefined
153 ;; Wood, D.C. (June 1992). The Computation of Polylogarithms. Technical Report 15-92
154 ;; University of Kent Computing Laboratory.
155 ;; http://www.cs.kent.ac.uk/pubs/1992/110
156 ;; equation 11.1
157 (defun li-asymptotic-expansion (pw s z)
158 (m+l (loop for k from 0 to pw collect
159 (m* (m^ -1 k)
160 (m- 1 (m^ 2 (m- 1 (m* 2 k))))
161 (m^ (m* 2 '$%pi) (m* 2 k))
162 (m// ($bern (m* 2 k))
163 `((mfactorial) ,(m* 2 k)))
164 (m// (m^ `((%log) ,(m- z)) (m- 2 (m* 2 k)))
165 ($gamma (m+ s 1 (m* -2 k))))))))
167 ;; Numerical evaluation for Chebyschev expansions of the first kind
169 (defun cheby (x chebarr)
170 (let ((bn+2 0.0) (bn+1 0.0))
171 (do ((i (floor (aref chebarr 0)) (1- i)))
172 ((< i 1) (- bn+1 (* bn+2 x)))
173 (setq bn+2
174 (prog1 bn+1 (setq bn+1 (+ (aref chebarr i)
175 (- (* 2.0 x bn+1) bn+2))))))))
177 (defun cheby-prime (x chebarr)
178 (- (cheby x chebarr)
179 (* (aref chebarr 1) 0.5)))
181 ;; These should really be calculated with minimax rational approximations.
182 ;; Someone has done LI[2] already, and this should be updated; I haven't
183 ;; seen any results for LI[3] yet.
185 (defun li2numer (y)
186 ;; Spence's function can be used to compute li[2] for 0 <= x <= 1.
187 ;; To compute the rest, we need the following identities:
189 ;; li[2](x) = -li[2](1/x)-log(-x)^2/2-%pi^2/6
190 ;; li[2](x) = li[2](1/(1-x)) + log(1-x)*log((1-x)/x^2)/2 - %pi^2/6
192 ;; The first tells us how to compute li[2] for x > 1. The result is complex.
193 ;; For x < 0, the second can be used, and the result is real.
195 ;; (See http://functions.wolfram.com/ZetaFunctionsandPolylogarithms/PolyLog2/17/01/01/)
196 (labels ((li2 (x)
197 (cond ((< x 0)
198 (+ (li2 (/ (- 1 x)))
199 (* 0.5 (log (- 1 x)) (log (/ (- 1 x) (* x x))))
200 (- (/ (cl:expt (float pi) 2) 6))))
201 ((< x 1)
202 (slatec:dspenc x))
203 ((= x 1)
204 (/ (cl:expt (float pi) 2) 6))
206 ;; li[2](x) = -li[2](1/x)-log(-x)^2/2-%pi^2/6
207 (- (+ (li2 (/ x))
208 (/ (cl:expt (cl:log (- x)) 2) 2)
209 (/ (cl:expt (float pi) 2) 6)))))))
210 (complexify (li2 y))))
213 (defvar *li2* (make-array 15. :initial-contents '(14.0 1.93506430 .166073033 2.48793229e-2
214 4.68636196e-3 1.0016275e-3 2.32002196e-4
215 5.68178227e-5 1.44963006e-5 3.81632946e-6
216 1.02990426e-6 2.83575385e-7 7.9387055e-8
217 2.2536705e-8 6.474338e-9)
218 :element-type 'flonum))
221 (defvar *li3* (make-array 15. :initial-contents '(14.0 1.95841721 8.51881315e-2 8.55985222e-3
222 1.21177214e-3 2.07227685e-4 3.99695869e-5
223 8.38064066e-6 1.86848945e-6 4.36660867e-7
224 1.05917334e-7 2.6478920e-8 6.787e-9
225 1.776536e-9 4.73417e-10)
226 :element-type 'flonum))
228 (defvar *s12* (make-array 18. :initial-contents '(17.0 1.90361778 .431311318 .100022507
229 2.44241560e-2 6.22512464e-3 1.64078831e-3
230 4.44079203e-4 1.22774942e-4 3.45398128e-5
231 9.85869565e-6 2.84856995e-6 8.31708473e-7
232 2.45039499e-7 7.2764962e-8 2.1758023e-8 6.546158e-9
233 1.980328e-9)
234 :element-type 'flonum))
236 (defun chebyli2 (x)
237 (* x (cheby-prime (/ (1+ (* x 4)) 3) *li2*)))
239 (defun chebyli3 (x)
240 (* x (cheby-prime (/ (1+ (* 4 x)) 3) *li3*)))
242 (defun chebys12 (x)
243 (* (/ (expt x 2) 4)
244 (cheby-prime (/ (1+ (* 4 x)) 3) *s12*)))
246 ;; subtitle polygamma routines
248 ;; gross efficiency hack, exp is a function of *k*, *k* should be mbind'ed
250 (defun msum (exp lo hi)
251 (if (< hi lo)
253 (let ((sum 0))
254 (do ((*k* lo (1+ *k*)))
255 ((> *k* hi) sum)
256 (declare (special *k*))
257 (setq sum (add2 sum (meval exp)))))))
260 (defun pole-err (exp)
261 (declare (special errorsw))
262 (cond (errorsw (throw 'errorsw t))
263 (t (merror (intl:gettext "Pole encountered in: ~M") exp))))
266 (declare-top (special $maxpsiposint $maxpsinegint $maxpsifracnum $maxpsifracdenom))
268 (defprop $psi psisimp specsimp)
270 ;; Integral of psi function psi[n](x)
271 (putprop '$psi
272 `((n x)
274 ,(lambda (n x)
275 (cond
276 ((and ($integerp n) (>= n 0))
277 (cond
278 ((= n 0) `((%log_gamma) ,x))
279 (t `((mqapply) (($psi array) ((mplus) -1 ,n)) ,x))))
280 (t nil))))
281 'integral)
283 (mapcar #'(lambda (var val)
284 (and (not (boundp var)) (setf (symbol-value var) val)))
285 '($maxpsiposint $maxpsinegint $maxpsifracnum $maxpsifracdenom)
286 '(20. -10. 6 6))
288 (defun psisimp (expr a z)
289 (let ((s (simpcheck (car (subfunsubs expr)) z)))
290 (subargcheck expr 1 1 '$psi)
291 (setq a (simpcheck (car (subfunargs expr)) z))
292 (and (setq z (integer-representation-p a))
293 (< z 1)
294 (pole-err expr))
295 (eqtest (psisimp1 s a) expr)))
297 ;; This gets pretty hairy now.
299 (defun psisimp1 (s a)
300 (let ((*k*))
301 (declare (special *k*))
303 (and (integerp s) (>= s 0) (mnumericalp a)
304 (let (($float2bf t)) ($float (mfuncall '$bfpsi s a 18))))
305 (and (integerp s) (>= s 0) ($bfloatp a)
306 (mfuncall '$bfpsi s a $fpprec))
307 (and (not $numer) (not $float) (integerp s) (> s -1)
308 (cond
309 ((integerp a)
310 (and (not (> a $maxpsiposint)) ; integer values
311 (m*t (expt -1 s) (factorial s)
312 (m- (msum (inv (m^t '*k* (1+ s))) 1 (1- a))
313 (cond ((zerop s) '$%gamma)
314 (($zeta (1+ s))))))))
315 ((or (not (ratnump a)) (ratgreaterp a $maxpsiposint)) ())
316 ((ratgreaterp a 0)
317 (cond
318 ((ratgreaterp a 1)
319 (let* ((int ($entier a)) ; reduction to fractional values
320 (frac (m-t a int)))
321 (m+t
322 (psisimp1 s frac)
323 (if (> int $maxpsiposint)
324 (subfunmakes '$psi (ncons s) (ncons int))
325 (m*t (expt -1 s) (factorial s)
326 (msum (m^t (m+t (m-t a int) '*k*)
327 (1- (- s)))
328 0 (1- int)))))))
329 ((= s 0)
330 (let ((p (cadr a)) (q (caddr a)))
331 (cond
332 ((or (> p $maxpsifracnum)
333 (> q $maxpsifracdenom) (bignump p) (bignump q)) ())
334 ((and (= p 1)
335 (cond ((= q 2)
336 (m+ (m* -2 '((%log) 2)) (m- '$%gamma)))
337 ((= q 3)
338 (m+ (m* '((rat simp) -1 2)
339 (m^t 3 '((rat simp) -1 2)) '$%pi)
340 (m* '((rat simp) -3 2) '((%log) 3))
341 (m- '$%gamma)))
342 ((= q 4)
343 (m+ (m* '((rat simp) -1 2) '$%pi)
344 (m* -3 '((%log) 2)) (m- '$%gamma)))
345 ((= q 6)
346 (m- (m+ (m* '((rat simp) 3 2) '((%log) 3))
347 (m* 2 '((%log) 2))
348 (m* '((rat simp) 1 2) '$%pi
349 (m^t 3 '((rat simp) 1 2)))
350 '$%gamma))))))
351 ((and (= p 2) (= q 3))
352 (m+ (m* '((rat simp) 1 2)
353 (m^t 3 '((rat simp) -1 2)) '$%pi)
354 (m* '((rat simp) -3 2) '((%log) 3))
355 (m- '$%gamma)))
356 ((and (= p 3) (= q 4))
357 (m+ (m* '((rat simp) 1 2) '$%pi)
358 (m* -3 '((%log) 2)) (m- '$%gamma)))
359 ((and (= p 5) (= q 6))
360 (m- (m* '((rat simp) 1 2) '$%pi
361 (m^t 3 '((rat simp) 1 2)))
362 (m+ (m* '((rat simp) 3 2) '((%log) 3))
363 (m* 2 '((%log) 2))
364 '$%gamma)))
365 ;; Gauss's Formula
366 ((let ((f (m* `((%cos) ,(m* 2 a '$%pi '*k*))
367 `((%log) ,(m-t 2 (m* 2 `((%cos)
368 ,(m//t (m* 2 '$%pi '*k*)
369 q))))))))
370 (m+t (msum f 1 (1- (truncate q 2)))
371 (let ((*k* (truncate q 2)))
372 (declare (special *k*))
373 (m*t (meval f)
374 (cond ((oddp q) 1)
375 ('((rat simp) 1 2)))))
376 (m-t (m+ (m* '$%pi '((rat simp) 1 2)
377 `((%cot) ((mtimes simp) ,a $%pi)))
378 `((%log) ,q)
379 '$%gamma))))))))
380 ((alike1 a '((rat) 1 2))
381 (m*t (expt -1 (1+ s)) (factorial s)
382 (1- (expt 2 (1+ s))) (simplify ($zeta (1+ s)))))
383 ((and (ratgreaterp a '((rat) 1 2))
384 (ratgreaterp 1 a))
385 (m*t
386 (expt -1 s)
387 (m+t (psisimp1 s (m- 1 a))
388 (let ((dif (m* '$%pi
389 ($diff `((%cot) ,(m* '$%pi '$z)) '$z s)))
390 ($z (m-t a)))
391 (declare (special $z))
392 (meval dif)))))))
393 ((ratgreaterp a $maxpsinegint) ;;; Reflection Formula
394 (m*t
395 (expt -1 s)
396 (m+t (m+t (psisimp1 s (m- a))
397 (let ((dif (m* '$%pi
398 ($diff `((%cot) ,(m* '$%pi '$z)) '$z s)))
399 ($z (m-t a)))
400 (declare (special $z))
401 (meval dif)))
402 (m*t (factorial s) (m^t (m-t a) (1- (- s)))))))))
403 (subfunmakes '$psi (ncons s) (ncons a)))))
406 ;; subtitle polygamma tayloring routines
408 ;; These routines are specially coded to be as fast as possible given the
409 ;; current $TAYLOR; too bad they have to be so ugly.
411 (declare-top (special var subl *last* sign last-exp))
413 (defun expgam-fun (pw temp)
414 (setq temp (get-datum (get-key-var (car var))))
415 (let-pw temp pw
416 (pstimes
417 (let-pw temp (e1+ pw)
418 (psexpt-fn (getexp-fun '(($psi) -1) var (e1+ pw))))
419 (make-ps var (ncons pw) '(((-1 . 1) 1 . 1))))))
421 (defun expplygam-funs (pw subl l) ; l is a irrelevant here
422 (setq subl (car subl))
423 (if (or (not (integerp subl)) (< subl -1))
424 (tay-err "Unable to expand at a subscript in")
425 (prog ((e 0) (sign 0) npw)
426 (declare (fixnum e) (fixnum sign))
427 (setq npw (/ (float (car pw)) (float (cdr pw))))
428 (setq
429 l (cond ((= subl -1)
430 `(((1 . 1) . ,(prep1 '((mtimes) -1 $%gamma)))))
431 ((= subl 0)
432 (cons '((-1 . 1) -1 . 1)
433 (if (> 0.0 npw) ()
434 `(((0 . 1)
435 . ,(prep1 '((mtimes) -1 $%gamma)))))))
436 (t (setq *last* (factorial subl))
437 `(((,(- (1+ subl)) . 1)
438 ,(* (expt -1 (1+ subl))
439 (factorial subl)) . 1))))
440 e (if (< subl 1) (- subl) -1)
441 sign (if (< subl 1) -1 (expt -1 subl)))
442 a (setq e (1+ e) sign (- sign))
443 (if (> e npw) (return l)
444 (rplacd (last l)
445 `(((,e . 1)
446 . ,(rctimes (rcplygam e)
447 (prep1 ($zeta (+ (1+ subl) e))))))))
448 (go a))))
450 (defun rcplygam (k)
451 (declare (fixnum k) )
452 (cond ((= subl -1) (cons sign k))
453 ((= subl 0) (cons sign 1))
454 (t (prog1
455 (cons (* sign *last*) 1)
456 (setq *last*
457 (quot (* *last* (+ subl (1+ k)))
458 (1+ k)))))))
460 (defun plygam-ord (subl)
461 (if (equal (car subl) -1) (ncons (rcone))
462 `((,(m- (m1+ (car subl))) . 1))))
464 (defun plygam-pole (a c func)
465 (if (rcmintegerp c)
466 (let ((ps (get-lexp (m- a (rcdisrep c)) () t)))
467 (rplacd (cddr ps) (cons `((0 . 1) . ,c) (cdddr ps)))
468 (if (atom func) (gam-const a ps func)
469 (plygam-const a ps func)))
470 (prep1 (simplifya
471 (if (atom func) `((%gamma) ,(rcdisrep c))
472 `((mqapply) ,func ,(rcdisrep c)))
473 () ))))
475 (defun gam-const (a arg func)
476 (let ((const (ps-lc* arg)) (arg-c))
477 (cond ((not (rcintegerp const))
478 (taylor2 (diff-expand `((%gamma) ,a) tlist)))
480 (setq const (car const))
481 (if (pscoefp arg) (setq arg-c (get-lexp (m+t a (- const)) (rcone) (signp le const))))
482 (if (and arg-c (not (psp arg-c)))
483 (taylor2 (simplify `((%gamma) ,const)))
484 (let ((datum (get-datum (get-key-var (gvar (or arg-c arg)))))
485 (ord (if arg-c (le (terms arg-c)) (le (n-term (terms arg))))))
486 (setq func (current-trunc datum))
487 (if (> const 0)
488 (pstimes (let-pw datum (e- func ord) (expand (m+t a (- const)) '%gamma))
489 (let-pw datum (e+ func ord)
490 (tsprsum (m+t a (m-t '%%taylor-index%%))
491 `(%%taylor-index%% 1 ,const) '%product)))
492 (pstimes (expand (m+t a (- const)) '%gamma)
493 (let-pw datum (e+ func ord)
494 (psexpt (tsprsum (m+t a '%%taylor-index%%)
495 `(%%taylor-index%% 0 ,(- (1+ const))) '%product)
496 (rcmone)))))))))))
498 (defun plygam-const (a arg func)
499 (let ((const (ps-lc* arg)) (sub (cadr func)))
500 (cond
501 ((or (not (integerp sub)) (< sub -1))
502 (tay-err "Unable to expand at a subscript in"))
503 ((not (rcintegerp const))
504 (taylor2 (diff-expand `((mqapply) ,func ,a) tlist)))
505 (t (setq const (car const))
506 (psplus
507 (expand (m+t a (- const)) func)
508 (if (> const 0)
509 (pstimes
510 (cons (* (expt -1 sub) (factorial sub)) 1)
511 (tsprsum `((mexpt) ,(m+t a (m-t '%%taylor-index%%)) ,(- (1+ sub)))
512 `(%%taylor-index%% 1 ,const) '%sum))
513 (pstimes
514 (cons (* (expt -1 (1+ sub)) (factorial sub)) 1)
515 (tsprsum `((mexpt) ,(m+t a '%%taylor-index%%) ,(- (1+ sub)))
516 `(%%taylor-index%% 0 ,(- (1+ const))) '%sum))))))))
518 (declare-top (unspecial var subl *last* sign last-exp))
520 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
521 ;;; Lambert W function
522 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
524 ;; References
526 ;; Corless, R. M., Gonnet, D. E. G., Jeffrey, D. J., Knuth, D. E. (1996).
527 ;; "On the Lambert W function". Advances in Computational Mathematics 5:
528 ;; pp 329-359
530 ;; http://www.apmaths.uwo.ca/~djeffrey/Offprints/W-adv-cm.pdf.
531 ;; or http://www.apmaths.uwo.ca/~rcorless/frames/PAPERS/LambertW/
533 ;; D. J. Jeffrey, D. E. G. Hare, R. M. Corless
534 ;; Unwinding the branches of the Lambert W function
535 ;; The Mathematical Scientist, 21, pp 1-7, (1996)
536 ;; http://www.apmaths.uwo.ca/~djeffrey/Offprints/wbranch.pdf
538 ;; Winitzki, S. Uniform Approximations for Transcendental Functions.
539 ;; In Part 1 of Computational Science and its Applications - ICCSA 2003,
540 ;; Lecture Notes in Computer Science, Vol. 2667, Springer-Verlag,
541 ;; Berlin, 2003, 780-789. DOI 10.1007/3-540-44839-X_82
542 ;; http://homepages.physik.uni-muenchen.de/~Winitzki/papers/
544 ;; Darko Verebic,
545 ;; Having Fun with Lambert W(x) Function
546 ;; arXiv:1003.1628v1, March 2010, http://arxiv.org/abs/1003.1628
548 ;; See also http://en.wikipedia.org/wiki/Lambert's_W_function
550 (defmfun $lambert_w (z)
551 (simplify (list '(%lambert_w) (resimplify z))))
553 ;;; Set properties to give full support to the parser and display
554 (defprop $lambert_w %lambert_w alias)
555 (defprop $lambert_w %lambert_w verb)
556 (defprop %lambert_w $lambert_w reversealias)
557 (defprop %lambert_w $lambert_w noun)
559 ;;; lambert_w is a simplifying function
560 (defprop %lambert_w simp-lambertw operators)
562 ;;; Derivative of lambert_w
563 (defprop %lambert_w
564 ((x)
565 ((mtimes)
566 ((mexpt) $%e ((mtimes ) -1 ((%lambert_w) x)))
567 ((mexpt) ((mplus) 1 ((%lambert_w) x)) -1)))
568 grad)
570 ;;; Integral of lambert_w
571 ;;; integrate(W(x),x) := x*(W(x)^2-W(x)+1)/W(x)
572 (defprop %lambert_w
573 ((x)
574 ((mtimes)
576 ((mplus)
577 ((mexpt) ((%lambert_w) x) 2)
578 ((mtimes) -1 ((%lambert_w) x))
580 ((mexpt) ((%lambert_w) x) -1)))
581 integral)
583 (defun simp-lambertw (x yy z)
584 (declare (ignore yy))
585 (oneargcheck x)
586 (setq x (simpcheck (cadr x) z))
587 (cond ((equal x 0) 0)
588 ((equal x 0.0) 0.0)
589 ((zerop1 x) ($bfloat 0)) ;bfloat case
590 ((alike1 x '$%e)
591 ;; W(%e) = 1
593 ((alike1 x '((mtimes simp) ((rat simp) -1 2) ((%log simp) 2)))
594 ;; W(-log(2)/2) = -log(2)
595 '((mtimes simp) -1 ((%log simp) 2)))
596 ((alike1 x '((mtimes simp) -1 ((mexpt simp) $%e -1)))
597 ;; W(-1/e) = -1
599 ((alike1 x '((mtimes) ((rat) -1 2) $%pi))
600 ;; W(-%pi/2) = %i*%pi/2
601 '((mtimes simp) ((rat simp) 1 2) $%i $%pi))
602 ;; numerical evaluation
603 ((complex-float-numerical-eval-p x)
604 ;; x may be an integer. eg "lambert_w(1),numer;"
605 (if (integerp x)
606 (to (bigfloat::lambert-w-k 0 (bigfloat:to ($float x))))
607 (to (bigfloat::lambert-w-k 0 (bigfloat:to x)))))
608 ((complex-bigfloat-numerical-eval-p x)
609 (to (bigfloat::lambert-w-k 0 (bigfloat:to x))))
610 (t (list '(%lambert_w simp) x))))
612 ;; An approximation of the k-branch of generalized Lambert W function
613 ;; k integer
614 ;; z real or complex lisp float
615 ;; Used as initial guess for Halley's iteration.
616 ;; When W(z) is real, ensure that guess is real.
617 (defun init-lambert-w-k (k z)
618 (let ( ; parameters for k = +/- 1 near branch pont z=-1/%e
619 (branch-eps 0.2e0)
620 (branch-point (/ -1 %e-val))) ; branch pont z=-1/%e
621 (cond
622 ; For principal branch k=0, use expression by Winitzki
623 ((= k 0) (init-lambert-w-0 z))
624 ; For k=1 branch, near branch point z=-1/%e with im(z) < 0
625 ((and (= k 1)
626 (< (imagpart z) 0)
627 (< (abs (- branch-point z)) branch-eps))
628 (bigfloat::lambert-branch-approx z))
629 ; For k=-1 branch, z real with -1/%e < z < 0
630 ; W(z) is real in this range
631 ((and (= k -1) (realp z) (> z branch-point) (< z 0))
632 (init-lambert-w-minus1 z))
633 ; For k=-1 branch, near branch point z=-1/%e with im(z) >= 0
634 ((and (= k -1)
635 (>= (imagpart z) 0)
636 (< (abs (- branch-point z)) branch-eps))
637 (bigfloat::lambert-branch-approx z))
638 ; Default to asymptotic expansion Corless et al (4.20)
639 ; W_k(z) = log(z) + 2.pi.i.k - log(log(z)+2.pi.i.k)
640 (t (let ((two-pi-i-k (complex 0.0e0 (* 2 pi k))))
641 (+ (log z)
642 two-pi-i-k
643 (* -1 (log (+ (log z) two-pi-i-k )))))))))
645 ;; Complex value of the principal branch of Lambert's W function in
646 ;; the entire complex plane with relative error less than 1%, given
647 ;; standard branch cuts for sqrt(z) and log(z).
648 ;; Winitzki (2003)
649 (defun init-lambert-w-0 (z)
650 (let ((a 2.344e0) (b 0.8842e0) (c 0.9294e0) (d 0.5106e0) (e -1.213e0)
651 (y (sqrt (+ (* 2 %e-val z ) 2)) ) ) ; y=sqrt(2*%e*z+2)
652 ; w = (2*log(1+B*y)-log(1+C*log(1+D*y))+E)/(1+1/(2*log(1+B*y)+2*A)
654 (+ (* 2 (log (+ 1 (* b y))))
655 (* -1 (log (+ 1 (* c (log (+ 1 (* d y)))))))
657 (+ 1
658 (/ 1 (+ (* 2 (log (+ 1 (* b y)))) (* 2 a)))))))
660 ;; Approximate k=-1 branch of Lambert's W function over -1/e < z < 0.
661 ;; W(z) is real, so we ensure the starting guess for Halley iteration
662 ;; is also real.
663 ;; Verebic (2010)
664 (defun init-lambert-w-minus1 (z)
665 (cond
666 ((not (realp z))
667 (merror "z not real in init-lambert-w-minus1"))
668 ((or (< z (/ -1 %e-val)) (plusp z))
669 (merror "z outside range of approximation in init-lambert-w-minus1"))
670 ;; In the region where W(z) is real
671 ;; -1/e < z < C, use power series about branch point -1/e ~ -0.36787
672 ;; C = -0.3 seems a reasonable crossover point
673 ((< z -0.3)
674 (bigfloat::lambert-branch-approx z))
675 ;; otherwise C <= z < 0, use iteration W(z) ~ ln(-z)-ln(-W(z))
676 ;; nine iterations are sufficient over -0.3 <= z < 0
677 (t (let* ((ln-z (log (- z))) (maxiter 9) (w ln-z))
678 (dotimes (k maxiter w)
679 (setq w (- ln-z (log (- w)))))))))
681 (in-package #-gcl #:bigfloat #+gcl "BIGFLOAT")
683 ;; Approximate Lambert W(k,z) for k=1 and k=-1 near branch point z=-1/%e
684 ;; using power series in y=-sqrt(2*%e*z+2)
685 ;; for im(z) < 0, approximates k=1 branch
686 ;; for im(z) >= 0, approximates k=-1 branch
688 ;; Corless et al (1996) (4.22)
689 ;; Verebic (2010)
691 ;; z is a real or complex bigfloat:
692 (defun lambert-branch-approx (z)
693 (let ((y (- (sqrt (+ (* 2 (%e z) z ) 2)))) ; y=-sqrt(2*%e*z+2)
694 (b0 -1) (b1 1) (b2 -1/3) (b3 11/72))
695 (+ b0 (* y (+ b1 (* y (+ b2 (* b3 y))))))))
697 ;; Algorithm based in part on Corless et al (1996).
699 ;; It is Halley's iteration applied to w*exp(w).
702 ;; w[j] exp(w[j]) - z
703 ;; w[j+1] = w[j] - -------------------------------------------------
704 ;; (w[j]+2)(w[j] exp(w[j]) -z)
705 ;; exp(w[j])(w[j]+1) - ---------------------------
706 ;; 2 w[j] + 2
708 ;; The algorithm has cubic convergence. Once convergence begins, the
709 ;; number of digits correct at step k is roughly 3 times the number
710 ;; which were correct at step k-1.
712 ;; Convergence can stall using convergence test abs(w[j+1]-w[j]) < prec,
713 ;; as happens for generalized_lambert_w(-1,z) near branch point z = -1/%e
714 ;; Therefore also stop iterating if abs(w[j]*exp(w[j]) - z) << abs(z)
715 (defun lambert-w-k (k z &key (maxiter 50))
716 (let ((w (init-lambert-w-k k z)) we w1e delta (prec (* 4 (epsilon z))))
717 (dotimes (i maxiter (maxima::merror "lambert-w-k did not converge"))
718 (setq we (* w (exp w)))
719 (when (<= (abs (- z we)) (* 4 (epsilon z) (abs z))) (return))
720 (setq w1e (* (1+ w) (exp w)))
721 (setq delta (/ (- we z)
722 (- w1e (/ (* (+ w 2) (- we z)) (+ 2 (* 2 w))))))
723 (decf w delta)
724 (when (<= (abs (/ delta w)) prec) (return)))
725 ;; Check iteration converged to correct branch
726 (check-lambert-w-k k w z)
729 (defmethod init-lambert-w-k ((k integer) (z number))
730 (maxima::init-lambert-w-k k z))
732 (defmethod init-lambert-w-k ((k integer) (z bigfloat))
733 (bfloat-init-lambert-w-k k z))
735 (defmethod init-lambert-w-k ((k integer) (z complex-bigfloat))
736 (bfloat-init-lambert-w-k k z))
738 (defun bfloat-init-lambert-w-k (k z)
739 "Approximate generalized_lambert_w(k,z) for bigfloat: z as initial guess"
740 (let ((branch-point -0.36787944117144)) ; branch point -1/%e
741 (cond
742 ;; if k=-1, z very close to -1/%e and imag(z)>=0, use power series
743 ((and (= k -1)
744 (or (zerop (imagpart z))
745 (plusp (imagpart z)))
746 (< (abs (- z branch-point)) 1e-10))
747 (lambert-branch-approx z))
748 ;; if k=1, z very close to -1/%e and imag(z)<0, use power series
749 ((and (= k 1)
750 (minusp (imagpart z))
751 (< (abs (- z branch-point)) 1e-10))
752 (lambert-branch-approx z))
753 ;; Initialize using float value if z is representable as a float
754 ((< (abs z) 1.0e100)
755 (if (complexp z)
756 (bigfloat (lambert-w-k k (cl:complex (float (realpart z) 1.0)
757 (float (imagpart z) 1.0))))
758 (bigfloat (lambert-w-k k (float z 1.0)))))
759 ;; For large z, use Corless et al (4.20)
760 ;; W_k(z) ~ log(z) + 2.pi.i.k - log(log(z)+2.pi.i.k)
762 (let ((log-z (log z)))
763 (if (= k 0)
764 (- log-z (log log-z))
765 (let* ((i (make-instance 'complex-bigfloat :imag (intofp 1)))
766 (two-pi-i-k (* 2 (%pi z) i k)))
767 (- (+ log-z two-pi-i-k)
768 (log (+ log-z two-pi-i-k))))))))))
770 ;; Check Lambert W iteration converged to the correct branch
771 ;; W_k(z) + ln W_k(z) = ln z, for k = -1 and z in [-1/e,0)
772 ;; = ln z + 2 pi i k, otherwise
773 ;; See Jeffrey, Hare, Corless (1996), eq (12)
774 ;; k integer
775 ;; z, w bigfloat: numbers
776 (defun check-lambert-w-k (k w z)
777 (let ((tolerance #-gcl 1.0e-6
778 #+gcl (cl:float 1/1000000)))
780 (cond
781 ;; k=-1 branch with z and w real.
782 ((and (= k -1) (realp z) (minusp z) (>= z (/ -1 (%e z))))
783 (if (and (realp w)
784 (<= w -1)
785 (< (abs (+ w (log w) (- (log z)))) tolerance))
787 nil))
789 ; i k = (W_k(z) + ln W_k(z) - ln(z)) / 2 pi
790 (let (ik)
791 (setq ik (/ (+ w (log w) (- (log z))) (* 2 (%pi z))))
792 (if (and (< (realpart ik) tolerance)
793 (< (abs (- k (imagpart ik))) tolerance))
795 nil))))
797 (maxima::merror "Lambert W iteration converged to wrong branch"))))
799 (in-package :maxima)
801 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
802 ;;; Generalized Lambert W function
803 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
805 (defmfun $generalized_lambert_w (k z)
806 (simplify (list '(%generalized_lambert_w) (resimplify k) (resimplify z))))
808 ;;; Set properties to give full support to the parser and display
809 (defprop $generalized_lambert_w %generalized_lambert_w alias)
810 (defprop $generalized_lambert_w %generalized_lambert_w verb)
811 (defprop %generalized_lambert_w $generalized_lambert_w reversealias)
812 (defprop %generalized_lambert_w $generalized_lambert_w noun)
814 ;;; lambert_w is a simplifying function
815 (defprop %generalized_lambert_w simp-generalized-lambertw operators)
817 ;;; Derivative of lambert_w
818 (defprop %generalized_lambert_w
819 ((k x)
821 ((mtimes)
822 ((mexpt) $%e ((mtimes ) -1 ((%generalized_lambert_w) k x)))
823 ((mexpt) ((mplus) 1 ((%generalized_lambert_w) k x)) -1)))
824 grad)
826 ;;; Integral of lambert_w
827 ;;; integrate(W(k,x),x) := x*(W(k,x)^2-W(k,x)+1)/W(k,x)
828 (defprop %generalized_lambert_w
829 ((k x)
831 ((mtimes)
833 ((mplus)
834 ((mexpt) ((%generalized_lambert_w) k x) 2)
835 ((mtimes) -1 ((%generalized_lambert_w) k x))
837 ((mexpt) ((%generalized_lambert_w) k x) -1)))
838 integral)
840 (defun simp-generalized-lambertw (expr ignored z)
841 (declare (ignore ignored))
842 (twoargcheck expr)
843 (let ((k (simpcheck (cadr expr) z))
844 (x (simpcheck (caddr expr) z)))
845 (cond
846 ;; Numerical evaluation for real or complex x
847 ((and (integerp k) (complex-float-numerical-eval-p x))
848 ;; x may be an integer. eg "generalized_lambert_w(0,1),numer;"
849 (if (integerp x)
850 (to (bigfloat::lambert-w-k k (bigfloat:to ($float x))))
851 (to (bigfloat::lambert-w-k k (bigfloat:to x)))))
852 ;; Numerical evaluation for real or complex bigfloat x
853 ((and (integerp k) (complex-bigfloat-numerical-eval-p x))
854 (to (bigfloat::lambert-w-k k (bigfloat:to x))))
855 (t (list '(%generalized_lambert_w simp) k x)))))
857 (in-package "BIGFLOAT")
859 (defvar *debug-li-eval* nil)
861 (defun li-using-powers-of-log (n x)
862 ;; When x is on or near the unit circle the other
863 ;; approaches don't work. Use the expansion in powers of
864 ;; log(z) (from cephes cpolylog)
866 ;; li[s](z) = sum(Z(s-j)*(log(z))^j/j!, j = 0, inf)
868 ;; where Z(j) = zeta(j) for j != 1. For j = 1:
870 ;; Z(1) = -log(-log(z)) + sum(1/k, k, 1, s - 1)
873 ;; This is similar to
874 ;; http://functions.wolfram.com/10.08.06.0024.01, but that
875 ;; identity is clearly undefined if v is a positive
876 ;; integer because zeta(1) is undefined.
878 ;; Thus,
880 ;; li[3](z) = Z(3) + Z(2)*log(z) + Z(1)*log(z)^2/2!
881 ;; + Z(0)*log(z)^3/3! + sum(Z(-k)*log(z)^(k+4)/(k+4)!,k,1,inf);
883 ;; But Z(-k) = zeta(-k) is 0 if k is even. So
885 ;; li[3](z) = Z(3) + Z(2)*log(z) + Z(1)*log(z)^2/2!
886 ;; + Z(0)*log(z)^3/3! + sum(Z(-(2*k+1))*log(z)^(2*k+4)/(2*k+4)!,k,0,inf);
887 (flet ((zfun (j)
888 (cond ((= j 1)
889 (let ((sum (- (log (- (log x))))))
890 (+ sum
891 (loop for k from 1 below n
892 sum (/ k)))))
894 (to (maxima::$zeta (maxima::to (float j (realpart x)))))))))
895 (let* ((eps (epsilon x))
896 (logx (log x))
897 (sum 0))
898 (do* ((k 0 (1+ k))
899 (top 1 (* top logx))
900 (bot 1 (* bot k))
901 (term (* (/ top bot) (to (zfun (- n k))))
902 (* (/ top bot) (to (zfun (- n k))))))
903 ((and (> k 4)
904 (oddp (- n k)) ;; even terms are all zero
905 (<= (abs term) (* (abs sum) eps))))
906 ;;(format t "~3d: ~A / ~A = ~A~%" k top bot term)
907 (incf sum term))
908 sum)))
911 (defun li3numer (x)
912 ;; If |x| < series-threshold, the series is used.
913 (let ((series-threshold 0.8))
914 (cond ((zerop x)
915 0.0)
916 ((= x 1)
917 (maxima::$zeta (maxima::to (float 3 x))))
918 ((= x -1)
919 ;; li[3](-1) = -(1-2^(1-3))*li[3](1)
920 ;; = -3/4*zeta(3)
922 ;; From the formula
924 ;; li[s](-1) = (2^(1-s)-1)*zeta(s)
926 ;; (See http://functions.wolfram.com/10.08.03.0003.01)
927 (* -3/4 (to (maxima::$zeta (maxima::to (float 3 x))))))
928 ((> (abs x) 1)
929 ;; For z not in the interval (0, 1) and for integral n, we
930 ;; have the identity:
932 ;; li[n](z) = -log(-z)^n/n! + (-1)^(n-1)*li[n](1/z)
933 ;; + 2 * sum(li[2*r](-1)/(n-2*r)!*log(-z)^(n-2*r), r, 1, floor(n/2))
935 ;; (See http://functions.wolfram.com/ZetaFunctionsandPolylogarithms/PolyLog/17/02/01/01/0008/)
937 ;; In particular for n = 3:
939 ;; li[3](z) = li[3](1/z) - log(-z)/6*(log(-z)^2+%pi^2)
940 (let* ((lg (log (- x)))
941 (dpi (%pi x))
942 (result (- (li3numer (/ x))
943 (* (/ lg 6)
944 (+ (* lg lg) (* dpi dpi))))))
945 result))
946 ((> (abs x) series-threshold)
947 (let ((result (li-using-powers-of-log 3 x)))
948 ;; For real x, li-using-power-of-log can return a complex
949 ;; number with a tiny imaginary part. Get rid of that
950 ;; when x is real.
951 (if (realp x)
952 (realpart result)
953 result)))
954 ;; Don't use the identity below because the identity seems
955 ;; to be incorrect. For example, for x = -0.862 it returns
956 ;; a complex value with an imaginary part that is not close
957 ;; to zero as expected.
958 #+nil
959 ((> (abs x) series-threshold)
960 ;; The series converges too slowly so use the identity:
962 ;; li[3](-x/(1-x)) + li[3](1-x) + li[3](x)
963 ;; = li[3](1) + %pi^2/6*log(1-x) - 1/2*log(x)*(log(1-x))^2 + 1/6*(log(1-x))^3
965 ;; Or
967 ;; li[3](x) = li[3](1) + %pi^2/6*log(1-x) - 1/2*log(x)*(log(1-x))^2 + 1/6*(log(1-x))^3
968 ;; - li[3](-x/(1-x)) - li[3](1-x)
970 ;; (See http://functions.wolfram.com/10.08.17.0048.01)
971 (let* ((dpi (%pi x))
972 (u (log x))
973 (s (/ (* u u u) 6))
974 (xc (- 1 x)))
975 (decf s (* 0.5 u u (log xc)))
976 (incf s (/ (* dpi dpi u) 6))
977 (decf s (li3numer (- (/ xc x))))
978 (decf s (li3numer xc))
979 (incf s (li3numer (float 1 x)))))
981 ;; Sum the power series. threshold determines when the
982 ;; summation has converted.
983 (let* ((threshold (epsilon x))
984 (p (* x x x))
985 (term (/ p 27)))
986 (incf term (* 0.125 x x))
987 (incf term x)
988 (do* ((k 4 (1+ k))
989 (p1 (* p x) (* p1 x))
990 (h (/ p1 (* k k k)) (/ p1 (* k k k)))
991 (s h (+ s h)))
992 ((<= (abs (/ h s)) threshold)
993 (+ s term))))))))
995 (defun li2numer (z)
996 ;; The series threshold to above sqrt(1/2) because li[2](%i) needs
997 ;; the value of li[2](1/2-%i/2), and the magnitude of the argument
998 ;; is sqrt(1/2) = 0.707. If the threshold is below this, we get
999 ;; into an infinite recursion oscillating between the two args.
1000 (let ((series-threshold .75))
1001 (cond ((zerop z)
1003 ((= z 1)
1004 ;; %pi^2/6. This follows from the series.
1005 (/ (expt (%pi z) 2) 6))
1006 ((= z -1)
1007 ;; -%pi^2/12. From the formula
1009 ;; li[s](-1) = (2^(1-s)-1)*zeta(s)
1011 ;; (See http://functions.wolfram.com/10.08.03.0003.01)
1012 (/ (expt (%pi z) 2) -12))
1013 ((> (abs z) 1)
1014 ;; Use
1015 ;; li[2](z) = -li[2](1/z) - 1/2*log(-z)^2 - %pi^2/6,
1017 ;; valid for all z not in the intervale (0, 1).
1019 ;; (See http://functions.wolfram.com/10.08.17.0013.01)
1020 (- (+ (li2numer (/ z))
1021 (* 0.5 (expt (log (- z)) 2))
1022 (/ (expt (%pi z) 2) 6))))
1023 ;; this converges faster when close to unit circle
1024 ((> (abs z) series-threshold)
1025 (li-using-powers-of-log 2 z))
1026 ;; no longer in use
1027 ;;(> (abs z) series-threshold)
1028 ;; For 0.5 <= |z|, where the series would not converge very quickly, use
1030 ;; li[2](z) = li[2](1/(1-z)) + 1/2*log(1-z)^2 - log(-z)*log(1-z) - %pi^2/6
1032 ;; (See http://functions.wolfram.com/10.08.17.0016.01)
1033 ;;(let* ((1-z (- 1 z))
1034 ;; (ln (log 1-z)))
1035 ;; (+ (li2numer (/ 1-z))
1036 ;; (* 0.5 ln ln)
1037 ;; (- (* (log (- z))
1038 ;; ln))
1039 ;; (- (/ (expt (%pi z) 2) 6)))))
1041 ;; Series evaluation:
1043 ;; li[2](z) = sum(z^k/k^2, k, 1, inf);
1044 (let ((eps (epsilon z)))
1045 (do* ((k 0 (1+ k))
1046 (term z (* term (/ (* z k k)
1047 (expt (1+ k) 2))))
1048 (sum z (+ term sum)))
1049 ((<= (abs (/ term sum)) eps)
1050 sum)))))))
1052 (defun polylog-power-series (s z)
1053 ;; Series evaluation:
1055 ;; li[s](z) = sum(z^k/k^s, k, 1, inf);
1056 (let ((eps (epsilon z)))
1057 (do* ((k 1 (1+ k))
1058 (term z (* term z (expt (/ (- k 1) k) s)))
1059 (sum z (+ term sum)))
1060 ((<= (abs (/ term sum)) eps)
1061 ;; Return the value and the number of terms used, for
1062 ;; debugging and for helping in determining the series
1063 ;; threshold.
1064 (values sum k)))))
1066 (defun polylog-log-series (s z)
1067 ;; When x is on or near the unit circle the other
1068 ;; approaches don't work. Use the expansion in powers of
1069 ;; log(z) (from cephes cpolylog)
1071 ;; li[s](z) = sum(Z(s-j)*(log(z))^j/j!, j = 0, inf)
1073 ;; where Z(j) = zeta(j) for j != 1. For j = 1:
1075 ;; Z(1) = -log(-log(z)) + sum(1/k, k, 1, s - 1)
1076 (flet ((zfun (j)
1077 ;; Compute Z(j)
1078 (cond ((= j 1)
1079 (let ((sum (- (log (- (log z))))))
1080 (+ sum
1081 (loop for k from 1 below s
1082 sum (/ k)))))
1084 (to (maxima::$zeta (maxima::to (float j (realpart z)))))))))
1085 (let* ((eps (epsilon z))
1086 (logx (log z))
1087 (logx^2 (* logx logx))
1088 (top logx)
1089 (bot 1)
1090 (sum (zfun s)))
1091 ;; Compute sum(Z(s-j)*log(z)^j/j!, j = 1, s)
1092 (do* ((k 1 (1+ k))
1093 (zf (zfun (- s k)) (zfun (- s k)))
1094 (term (* (/ top bot) zf)
1095 (* (/ top bot) zf)))
1096 ((> k s))
1097 (when *debug-li-eval*
1098 (format t "~3d: ~A / ~A * ~A => ~A~%" k top bot zf term))
1099 (incf sum term)
1100 (setf bot (* bot (1+ k)))
1101 (setf top (* top logx)))
1103 (when *debug-li-eval*
1104 (format t "s = ~A, sum = ~S top, bot = ~S ~S~%"
1105 s sum top bot))
1106 ;; Compute the sum for j = s+1 and up. But since
1107 ;; zeta(-k) is 0 for k even, we only every other term.
1108 (do* ((k (+ s 1) (+ k 2))
1109 (zf (zfun (- s k)) (zfun (- s k)))
1110 (term (* (/ top bot) zf)
1111 (* (/ top bot) zf)))
1112 ((<= (abs term) (* (abs sum) eps))
1113 ;; Return the result and the number of terms used for
1114 ;; helping in determining the series threshold and the
1115 ;; log-series threshold.
1117 ;; Note that if z is real and less than 0, li[s](z) is
1118 ;; real. The series can return a tiny complex value in
1119 ;; this case, so we want to clear that out before
1120 ;; returning the answer.
1121 (values (if (and (realp z) (minusp z))
1122 (realpart sum)
1123 sum)
1125 (when *debug-li-eval*
1126 (format t "~3d: ~A / ~A = ~A~%" k top bot term))
1127 (incf sum term)
1128 (setf bot (* bot (+ k 1) (+ k 2)))
1129 (setf top (* top logx^2))))))
1131 (defun polylog-inversion-formula (s z)
1132 ;; For z not in the interval (0, 1) and for integral n, we
1133 ;; have the identity:
1135 ;; li[n](z) = -log(-z)^n/n! + (-1)^(n-1)*li[n](1/z)
1136 ;; + 2 * sum(li[2*r](-1)/(n-2*r)!*log(-z)^(n-2*r), r, 1, floor(n/2))
1138 ;; (See http://functions.wolfram.com/ZetaFunctionsandPolylogarithms/PolyLog/17/02/01/01/0008/)
1140 ;; Or
1142 ;; li[n](z) = -log(-z)^n/n! + (-1)^(n-1)*li[n](1/z)
1143 ;; + 2 * sum(li[2*m-2*r](-1)/(n-2*m+2*r)!*log(-z)^(n-2*m+2*r), r, 0, m - 1)
1145 ;; where m = floor(n/2). Thus, n-2*m = 0 if n is even and 1 if n is odd.
1147 ;; For n = 2*m, we have
1149 ;; li[2*m](z) = -log(-z)^(2*m)/(2*m)! - li[2*m](1/z)
1150 ;; + 2 * sum(li[2*r](-1)/(2*m-2*r)!*log(-z)^(2*m-2*r), r, 1, m)
1151 ;; = -log(-z)^(2*m)/(2*m)! - li[2*m](1/z)
1152 ;; + 2 * sum((li[2*m-2*r](-1)*log(-z)^(2*r+1))/(2*r+1)!,r,0,m-1);
1154 ;; For n = 2*m+1, we have
1156 ;; li[2*m+1](z) = -log(-z)^(2*m+1)/(2*m+1)! + li[2*m+1](1/z)
1157 ;; + 2 * sum(li[2*r](-1)/(2*m-2*r + 1)!*log(-z)^(2*m-2*r + 1), r, 1, m)
1158 ;; = -log(-z)^(2*m+1)/(2*m+1)! + li[2*m+1](1/z)
1159 ;; + 2 * sum((li[2*m-2*r](-1)*log(-z)^(2*r+1))/(2*r+1)!,r,0,m-1);
1160 ;; Thus,
1162 ;; li[n](z) = -log(-z)^n/n! + (-1)^(n-1)*li[n](1/z)
1163 ;; + 2 * sum((li[2*m-2*r](-1)*log(-z)^(2*r+1))/(2*r+1)!,r,0,floor(n/2)-1);
1164 (let* ((lgz (log (- z)))
1165 (lgz^2 (* lgz lgz))
1166 (half-s (floor s 2))
1167 (neg-1 (float -1 (realpart z)))
1168 (sum 0))
1169 (if (evenp s)
1170 (do* ((r 0 (1+ r))
1171 (top (if (oddp s) lgz 1) (* top lgz^2))
1172 (bot 1 (* bot (+ r r -1) (+ r r)))
1173 (term (* (li-s-simp (* 2 (- half-s r)) neg-1)
1174 (/ top bot))
1175 (* (li-s-simp (* 2 (- half-s r)) neg-1)
1176 (/ top bot))))
1177 ((>= r half-s))
1178 (incf sum term)
1179 (when *debug-li-eval*
1180 (format t "r = ~4d: ~A / ~A, ~A; ~A~%" r top bot term sum)))
1181 (do* ((r 0 (1+ r))
1182 (top (if (oddp s) lgz 1) (* top lgz^2))
1183 (bot 1 (* bot (+ r r) (+ r r 1)))
1184 (term (* (li-s-simp (* 2 (- half-s r)) neg-1)
1185 (/ top bot))
1186 (* (li-s-simp (* 2 (- half-s r)) neg-1)
1187 (/ top bot))))
1188 ((>= r half-s))
1189 (incf sum term)
1190 (when *debug-li-eval*
1191 (format t "r = ~4d: ~A / ~A, ~A; ~A~%" r top bot term sum))))
1192 (+ (+ sum sum)
1193 (- (/ (expt lgz s)
1194 (maxima::take '(maxima::mfactorial) s)))
1195 (* (expt -1 (- s 1))
1196 (li-s-simp s (/ z))))))
1198 (defun li-s-simp (s z)
1199 (let ((series-threshold 0.5)
1200 (log-series-threshold 2))
1201 (cond ((zerop z)
1202 (maxima::to (to 0.0)))
1203 ((= z 1)
1204 (maxima::$zeta (maxima::to (float s z))))
1205 ((= z -1)
1206 (- (* (- 1 (expt 2 (- 1 s)))
1207 (to (li-s-simp s (- z))))))
1208 ((<= (abs z) series-threshold)
1209 (values (polylog-power-series s z)))
1210 ((<= (abs z) log-series-threshold)
1211 (values (polylog-log-series s z)))
1212 ((> (abs z) 1.5)
1213 (polylog-inversion-formula s z)))))