Rename *ll* and *ul* to ll and ul in limit-subs
[maxima.git] / src / expintegral.lisp
blob1d70111b6f0ee63290acde4a1098dc4dfeaffbc0
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;;;
3 ;;; Exponential Integrals
4 ;;;
5 ;;; This file contains the following Maxima User functions:
6 ;;;
7 ;;; $expintegral_e (n,z) - Exponential Integral En(z)
8 ;;; $expintegral_e1 (z) - Exponential Integral E1(z)
9 ;;; $expintegral_ei (z) - Exponential Integral Ei(z)
10 ;;;
11 ;;; $expintegral_li (z) - Logarithmic Integral Li(z)
12 ;;;
13 ;;; $expintegral_si (z) - Exponential Integral Si(z)
14 ;;; $expintegral_ci (z) - Exponential Integral Ci(z)
15 ;;;
16 ;;; $expintegral_shi (z) - Exponential Integral Shi(z)
17 ;;; $expintegral_chi (z) - Exponential Integral Chi(z)
18 ;;;
19 ;;; $expint (x) - Exponential Integral E1(x) (depreciated)
20 ;;;
21 ;;; Global variables for the Maxima User:
22 ;;;
23 ;;; $expintrep - Change the representation of the Exponential Integral to
24 ;;; gamma_incomplete, expintegral_e1, expintegral_ei,
25 ;;; expintegral_li, expintegral_trig, expintegral_hyp
26 ;;;
27 ;;; $expintexpand - Expand the Exponential Integral E[n](z)
28 ;;; for half integral values in terms of Erfc or Erf and
29 ;;; for positive integers in terms of Ei
30 ;;;
31 ;;; The following features are implemented:
32 ;;;
33 ;;; 1. Numerical evaluation for complex Flonum and Bigfloat numbers
34 ;;; using an expansion in a power series or continued fractions.
35 ;;; The numerical support is fully implemented for the E[n](z) function.
36 ;;; All other functions call E[n](z) for numerical evaluation.
37 ;;;
38 ;;; 2. For a negative integer parameter E[n](z) is automatically expanded in
39 ;;; a finite series in terms of powers and the Exponential function.
40 ;;;
41 ;;; 3. When $expintexpand is set to TRUE or ERF E[n](z) expands
42 ;;; a) for n a half integral number in terms of Erfc (TRUE) or Erf (ERF)
43 ;;; b) for n a positive integer number in terms of Ei
44 ;;;
45 ;;; 3. Simplifications for special values: Ev(0), E[0](z), Li(0), Li(1),...
46 ;;;
47 ;;; 4. Derivatives of the Exponential Integrals
48 ;;;
49 ;;; 5. Change the representation of every Exponential Integral through other
50 ;;; Exponential Integrals or the Incomplete Gamma function.
51 ;;;
52 ;;; 6. Mirror symmetry for all functions and reflection symmetry for
53 ;;; the Exponential Inegral Si and Shi are implemented.
54 ;;;
55 ;;; 7. Handling of taylor expansions as argument.
56 ;;;
57 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
58 ;;; This library is free software; you can redistribute it and/or modify it
59 ;;; under the terms of the GNU General Public License as published by the
60 ;;; Free Software Foundation; either version 2 of the License, or (at
61 ;;; your option) any later version.
62 ;;;
63 ;;; This library is distributed in the hope that it will be useful, but
64 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
65 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
66 ;;; Library General Public License for more details.
67 ;;;
68 ;;; You should have received a copy of the GNU General Public License along
69 ;;; with this library; if not, write to the Free Software
70 ;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
71 ;;;
72 ;;; Copyright (C) 2008 Dieter Kaiser
73 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
75 (in-package :maxima)
77 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
78 ;;; Globals to help debugging the code
79 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
81 (defvar *debug-expintegral* nil
82 "When enabled print debug information.")
84 (defvar *debug-expint-maxit* 0
85 "When in debug mode count the maximum of iterations needed by the algorithm.")
87 (defvar *debug-expint-fracmaxit* 0
88 "When in debug mode count the maximum of iterations needed by the algorithm.")
90 (defvar *debug-expint-bfloatmaxit* 0
91 "When in debug mode count the maximum of iterations needed by the algorithm.")
93 (defvar *debug-expint-fracbfloatmaxit* 0
94 "When in debug mode count the maximum of iterations needed by the algorithm.")
96 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
97 ;;; Globals for the Maxima Users
98 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
100 (defvar $expintexpand nil
101 "When not nil we expand for a half integral parameter of the Exponetial
102 Integral in a series in terms of the Erfc or Erf function and for positive
103 integer in terms of the Ei function.")
105 (defvar $expintrep nil
106 "Change the representation of the Exponential Integral.
107 Values are: gamma_incomplete, expintegral_e1, expintegral_ei,
108 expintegral_li, expintegral_trig, expintegral_hyp.")
110 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
111 ;;; Global to this file
112 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
114 (defvar *expintflag* '(%expintegral_e1 %expintegral_ei %expintegral_li
115 $expintegral_trig $expintegral_hyp %gamma_incomplete)
116 "Allowed flags to transform the Exponential Integral.")
118 (defun simp-domain-error (&rest args)
119 (if errorsw
120 (throw 'errorsw t)
121 (apply #'merror args)))
123 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
125 ;;; Part 1: The implementation of the Exponential Integral En
127 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
129 ;;; Exponential Integral E distributes over bags
131 (defprop %expintegral_e (mlist $matrix mequal) distribute_over)
133 ;;; Exponential Integral E has mirror symmetry,
134 ;;; but not on the real negative axis.
136 (defprop %expintegral_e conjugate-expintegral-e conjugate-function)
138 (defun conjugate-expintegral-e (args)
139 (let ((n (first args))
140 (z (second args)))
141 (cond ((off-negative-real-axisp z)
142 ;; Definitely not on the negative real axis for z. Mirror symmetry.
143 (take '(%expintegral_e)
144 (take '($conjugate) n)
145 (take '($conjugate) z)))
147 ;; On the negative real axis or no information. Unsimplified.
148 (list '($conjugate simp)
149 (take '(%expintegral_e) n z))))))
151 ;;; Differentiation of Exponential Integral E
153 (defprop %expintegral_e
154 ((n z)
155 ;; The derivative wrt the parameter n is expressed in terms of the
156 ;; Regularized Hypergeometric function 2F2 (see functions.wolfram.com)
157 ((mplus)
158 ((mtimes) -1
159 (($hypergeometric_regularized)
160 ((mlist)
161 ((mplus) 1 ((mtimes) -1 n))
162 ((mplus) 1 ((mtimes) -1 n)))
163 ((mlist)
164 ((mplus) 2 ((mtimes) -1 n))
165 ((mplus) 2 ((mtimes) -1 n)))
166 ((mtimes) -1 z))
167 ((mexpt)
168 ((%gamma) ((mplus) 1 ((mtimes) -1 n))) 2))
169 ((mtimes)
170 ((%gamma) ((mplus) 1 ((mtimes) -1 n)))
171 ((mexpt) z ((mplus) -1 n))
172 ((mplus)
173 ((mtimes) -1
174 ((mqapply)
175 (($psi array) 0)
176 ((mplus) 1 ((mtimes) -1 n))))
177 ((%log) z))))
179 ;; The derivative wrt the argument of the function
180 ((mtimes) -1 ((%expintegral_e) ((mplus) -1 n) z)))
181 grad)
183 ;;; Integral of Exponential Integral E
185 (defprop %expintegral_e
186 ((n z)
188 ((mtimes) -1 ((%expintegral_e) ((mplus) 1 n) z)))
189 integral)
191 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
193 ;;; We support a simplim%function. The function is looked up in simplimit and
194 ;;; handles specific values of the function.
196 (defprop %expintegral_e simplim%expintegral_e simplim%function)
198 (defun simplim%expintegral_e (expr var val)
199 ;; Look for the limit of the arguments.
200 (let ((a (limit (cadr expr) var val 'think))
201 (z (limit (caddr expr) var val 'think)))
202 (cond ((and (onep1 a)
203 (or (eq z '$zeroa)
204 (eq z '$zerob)
205 (zerop1 z)))
206 ;; Special case order a=1
207 '$inf)
209 ((member ($sign (add ($realpart a) -1)) '($neg $nz $zero))
210 ; realpart of order < 1
211 (cond ((eq z '$zeroa)
212 ;; from above, always inf
213 '$inf)
214 ((eq z '$zerob)
215 ;; this can be further improved to give a directed infinity
216 '$infinity)
217 ((zerop1 z)
218 ;; no direction, return infinity
219 '$infinity)
221 (ftake '%expintegral_e a z))))
223 ;; All other cases are handled by the simplifier of the function.
224 (ftake '%expintegral_e a z)))))
226 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
228 ;;; Exponential Integral E is a simplifying function
229 (def-simplifier expintegral_e (order arg)
230 (let ((ratorder))
231 (cond
232 ;; Check for special values
233 ((or (eq arg '$inf)
234 (alike1 arg '((mtimes) -1 $minf)))
235 ;; arg is inf or -minf, return zero
238 ((zerop1 arg)
239 (let ((sgn ($sign (add ($realpart order) -1))))
240 (cond
241 ((eq sgn '$pos)
242 ;; we handle the special case E[v](0) = 1/(v-1), for realpart(v)>1
243 (inv (add order -1)))
244 ((member sgn '($neg $nz $zero))
245 (simp-domain-error
246 (intl:gettext
247 "expintegral_e: expintegral_e(~:M,~:M) is undefined.")
248 order arg))
249 (t (give-up)))))
251 ((or (and (symbolp order) (member order *infinities*))
252 (and (symbolp arg) (member arg *infinities*)))
253 ;; order or arg is one of the infinities, we return a noun form,
254 ;; but we have already handled the special value inf for arg.
255 (give-up))
257 ((and (numberp order) (integerp order))
258 ;; The parameter of the Exponential integral is an integer. For this
259 ;; case we can do further simplifications or numerical evaluation.
260 (cond
261 ((= order 0)
262 ;; Special case E[0](z) = %e^(-z)/z, z<>0
263 ;; The case z=0 is already handled.
264 (div (power '$%e (mul -1 arg)) arg))
266 ((= order -1)
267 ;; Special case E[-1](0) = ((z+1)*%e^(-z))/z^2, z<>0
268 ;; The case z=0 is already handled.
269 (div (mul (power '$%e (mul -1 arg)) (add arg 1)) (mul arg arg)))
271 ((< order -1)
272 ;; We expand in a series, z<>0
273 (mul
274 (factorial (- order))
275 (power arg (+ order -1))
276 (power '$%e (mul -1 arg))
277 (let ((index (gensumindex)))
278 (dosum
279 (div (power arg index)
280 (take '(mfactorial) index))
281 index 0 (- order) t))))
283 ((and (> order 0)
284 (complex-float-numerical-eval-p arg))
285 ;; Numerical evaluation for double float real or complex arg
286 ;; order is an integer > 0 and arg <> 0 for order < 2
287 (let ((carg (complex ($float ($realpart arg))
288 ($float ($imagpart arg)))))
289 (complexify (expintegral-e order carg))))
291 ((and (> order 0)
292 (complex-bigfloat-numerical-eval-p arg))
293 ;; Numerical evaluation for Bigfloat real or complex arg.
294 (let* (($ratprint nil)
295 (carg (add ($bfloat ($realpart arg))
296 (mul '$%i ($bfloat ($imagpart arg)))))
297 (result (bfloat-expintegral-e order carg)))
298 (add ($realpart result) (mul '$%i ($imagpart result)))))
300 ((and $expintexpand (> order 0))
301 ;; We only expand in terms of the Exponential Integral Ei
302 ;; if the expand flag is set.
303 (sub (mul -1
304 (power (mul -1 arg) (- order 1))
305 (inv (factorial (- order 1)))
306 (add (take '(%expintegral_ei) (mul -1 arg))
307 (mul (inv 2)
308 (sub (take '(%log) (mul -1 (inv arg)))
309 (take '(%log) (mul -1 arg))))
310 (take '(%log) arg)))
311 (mul (power '$%e (mul -1 arg))
312 (let ((index (gensumindex)))
313 (dosum
314 (div (power arg (add index -1))
315 (take '($pochhammer) (- 1 order) index))
316 index 1 (- order 1) t)))))
318 ((eq $expintrep '%gamma_incomplete)
319 ;; We transform to the Incomplete Gamma function.
320 (mul (power arg (- order 1))
321 (take '(%gamma_incomplete) (- 1 order) arg)))
324 (give-up))))
326 ((complex-float-numerical-eval-p order arg)
327 (let (z)
328 (cond
329 ((and (setq z (integer-representation-p order))
330 (plusp z))
331 ;; We have a pure real positive order and the realpart is a float
332 ;; representation of an integer value.
333 ;; We call the routine for an integer order.
334 (let ((carg (complex ($float ($realpart arg))
335 ($float ($imagpart arg)))))
336 (complexify (expintegral-e z carg))))
338 ;; The general case, order and arg are complex or real.
339 (let ((corder (complex ($float ($realpart order))
340 ($float ($imagpart order))))
341 (carg (complex ($float ($realpart arg))
342 ($float ($imagpart arg)))))
343 (complexify (frac-expintegral-e corder carg)))))))
345 ((complex-bigfloat-numerical-eval-p order arg)
346 (let (z)
347 (cond
348 ((and (setq z (integer-representation-p order))
349 (plusp z))
350 ;; We have a real positive order and the realpart is a Float or
351 ;; Bigfloat representation of an integer value.
352 ;; We call the routine for an integer order.
353 (let* (($ratprint nil)
354 (carg (add ($bfloat ($realpart arg))
355 (mul '$%i ($bfloat ($imagpart arg)))))
356 (result (bfloat-expintegral-e z carg)))
357 (add ($realpart result)
358 (mul '$%i ($imagpart result)))))
360 ;; the general case, order and arg are bigfloat or complex bigfloat
361 (let* (($ratprint nil)
362 (corder (add ($bfloat ($realpart order))
363 (mul '$%i ($bfloat ($imagpart order)))))
364 (carg (add ($bfloat ($realpart arg))
365 (mul '$%i ($bfloat ($imagpart arg)))))
366 (result (frac-bfloat-expintegral-e corder carg)))
367 (add ($realpart result)
368 (mul '$%i ($imagpart result))))))))
370 ((and $expintexpand
371 (setq ratorder (max-numeric-ratio-p order 2)))
372 ;; We have a half integral order and $expintexpand is not NIL.
373 ;; We expand in a series in terms of the Erfc or Erf function.
374 (let ((func (cond ((eq $expintexpand '%erf)
375 (sub 1 ($erf (power arg '((rat simp) 1 2)))))
377 ($erfc (power arg '((rat simp) 1 2)))))))
378 (cond
379 ((= ratorder 1/2)
380 (mul (power '$%pi '((rat simp) 1 2))
381 (power arg '((rat simp) -1 2))
382 func))
383 ((= ratorder -1/2)
384 (add
385 (mul
386 (power '$%pi '((rat simp) 1 2))
387 (inv (mul 2 (power arg '((rat simp) 3 2))))
388 func)
389 (div (power '$%e (mul -1 arg)) arg)))
391 (let ((n (- ratorder 1/2)))
392 (mul
393 (power arg (sub n '((rat simp) 1 2)))
394 (add
395 (mul func (take '(%gamma) (sub '((rat simp) 1 2) n)))
396 (mul
397 (power '$%e (mul -1 arg))
398 (let ((index (gensumindex)))
399 (dosum
400 (div
401 (power arg (add index '((rat simp) 1 2)))
402 (take '($pochhammer)
403 (sub '((rat simp) 1 2) n)
404 (add index n 1)))
405 index 0 (mul -1 (add n 1)) t)))
406 (mul -1
407 (power '$%e (mul -1 arg))
408 (let ((index (gensumindex)))
409 (dosum
410 (div
411 (power arg (add index '((rat simp) 1 2)))
412 (take '($pochhammer)
413 (sub '((rat simp) 1 2) n)
414 (add index n 1)))
415 index (- n) -1 t))))))))))
417 ((eq $expintrep '%gamma_incomplete)
418 ;; We transform to the Incomplete Gamma function.
419 (mul (power arg (sub order 1))
420 (take '(%gamma_incomplete) (sub 1 order) arg)))
421 ($hypergeometric_representation
422 ;; See http://functions.wolfram.com/06.34.26.0002.01:
424 ;; expintegral_e(v,z) = z^(v-1)*gamma(1-v)
425 ;; - hypergeometric([1-v],[2-v], -z)
427 ;; But hypergeometric([1-v],[2-v],-z) gets simplified to
428 ;; hypergeometric([1],[2-v],z)*exp(-z)
429 (sub (mul (power arg (sub order 1))
430 (ftake '%gamma (sub 1 order)))
431 (div (ftake '%hypergeometric
432 (make-mlist (sub 1 order))
433 (make-mlist (sub 2 order))
434 (neg arg))
435 (sub 1 order))))
437 (give-up)))))
439 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
440 ;;; Numerical evaluation of the Exponential Integral En(z)
442 ;;; The following numerical routines are implemented:
444 ;;; expintegral-e - n positive integer, z real or complex
445 ;;; frac-expintegral-e - n,z real or complex; n not a positive integer
446 ;;; bfloat-expintegral-e - n positive integer,
447 ;;; z Bigfloat or Complex Bigfloat
448 ;;; frac-bfloat-expintegral-e - n Bigfloat, z Bigfloat or Complex Bigfloat
450 ;;; The algorithm are implemented for full support of Flonum and Bigfloat real
451 ;;; or Complex parameter and argument of the Exponential Integral.
452 ;;; Because we have no support for Complex Bigfloat arguments of the Gamma
453 ;;; function the evaluation for a Complex Bigfloat parameter don't give
454 ;;; the desiered accuracy.
456 ;;; The flonum versions return a CL complex number. The Bigfloat versions
457 ;;; a Maxima Complex Bigfloat number. It is assumed that the calling routine
458 ;;; check the values. We don't handle any special case. This has to be done by
459 ;;; the calling routine.
461 ;;; The evaluation uses an expansion in continued fractions for arguments with
462 ;;; realpart(z) > 0 and abs(z)> 1.0 (A&S 5.1.22). This expansion works for
463 ;;; every Real or Complex numbers including Bigfloat numbers for the parameter n
464 ;;; and the argument z:
466 ;;; 1 n 1 n+1 2
467 ;;; En(z) = e^(-z) * ( --- --- --- --- --- ... )
468 ;;; z+ 1+ z+ 1+ z+
470 ;;; The continued fraction is evaluated by the modified Lentz's method
471 ;;; for the more rapidly converging even form.
473 ;;; For the parameter n an positive integer we do an expansion in a power series
474 ;;; (A&S 5.1.12):
475 ;;; inf
476 ;;; ===
477 ;;; (-z)^(n-1) \ (-z)^m
478 ;;; En(z) = --------- * (-log(z)+psi(n)) * > ---------- ; n an integer
479 ;;; (n-1)! / (m-n+1)*m!
480 ;;; ===
481 ;;; m=0 (m <> n-1)
483 ;;; For an parameter n not an integer we expand in the following series
484 ;;; (functions.wolfram.com ):
485 ;;; inf
486 ;;; ===
487 ;;; \ (-1)^m * z^m
488 ;;; Ev(z) = gamma(1-v) * z^(v-1) * > ------------- ; n not an integer
489 ;;; / (m-v+1)*m!
490 ;;; ===
491 ;;; m=0
493 ;;; The evaluation stops if an accuracy better than *expint-eps* is achieved.
494 ;;; If the expansion don't converge within *expint-maxit* steps a Maxima
495 ;;; Error is thrown.
497 ;;; The algorithm is based on technics desribed in Numerical Recipes, 2nd Ed.
498 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
500 ;;; Constants to terminate the numerical evaluation
502 ;;; The accuracy *expint-eps* is fixed to 1.0e-15 for double float calculations.
503 ;;; The variable is declared global, so we can later give the Maxima User access
504 ;;; to the variable. The routine for Bigfloat numerical evaluation change this
505 ;;; value to the desired precision of the global $fpprec.
506 ;;; The maximum number of iterations is arbitrary set to 1000. For Bigfloat
507 ;;; evaluation this number is for very Big numbers too small.
509 ;;; The maximum iterations counted for the test file rtest-expintegral.mac are
510 ;;; 101 for Complex Flonum and 1672 for Complex Bigfloat evaluation.
512 (defvar *expint-eps* 1.0e-15)
513 (defvar *expint-maxit* 1000)
515 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
517 (defun expintegral-e (n z)
518 (declare (type integer n))
519 (let ((*expint-eps* *expint-eps*)
520 (*expint-maxit* *expint-maxit*)
521 ;; Add (complex) 0 to get rid of any signed zeroes, and make z
522 ;; be a complex number.
523 (z (+ (coerce 0 '(complex flonum)) z)))
524 (declare (type (complex flonum) z))
526 (when *debug-expintegral*
527 (format t "~&EXPINTEGRAL-E called with:~%")
528 (format t "~& : n = ~A~%" n)
529 (format t "~& : z = ~A~%" z))
531 (cond
532 ((or (and (> (abs z) 2.0) (< (abs (phase z)) (* pi 0.9)))
533 ;; (abs z)>2.0 is necessary since there is a point
534 ;; -1.700598-0.612828*%i which 1<(abs z)<2, phase z < 0.9pi and
535 ;; still c-f expansion does not converge.
536 (and (>= (realpart z) 0) (> (abs z) 1.0)))
537 ;; We expand in continued fractions.
538 (when *debug-expintegral*
539 (format t "~&We expand in continued fractions.~%"))
540 (let* ((b (+ z n))
541 (c (/ 1.0 (* *expint-eps* *expint-eps*)))
542 (d (/ 1.0 b))
543 (n1 (- n 1))
544 (h d)
545 (e 0.0))
546 (do* ((i 1 (+ i 1))
547 (a (* -1 n) (* (- i) (+ n1 i))))
548 ((> i *expint-maxit*)
549 (merror
550 (intl:gettext "expintegral_e: continued fractions failed.")))
552 (setq b (+ b 2.0))
553 (setq d (/ 1.0 (+ (* a d) b)))
554 (setq c (+ b (/ a c)))
555 (setq e (* c d))
556 (setq h (* h e))
558 (when (< (abs (- e 1.0)) *expint-eps*)
559 (when *debug-expintegral*
560 (setq *debug-expint-maxit* (max *debug-expint-maxit* i)))
561 (return (* h (exp (- z))))))))
563 ;; We expand in a power series.
564 (when *debug-expintegral*
565 (format t "~&We expand in a power series.~%"))
566 (let* ((n1 (- n 1))
567 (euler (mget '$%gamma '$numer))
568 (r (if (= n1 0) (- (- euler) (log z)) (/ 1.0 n1)))
569 (f 1.0)
570 (e 0.0))
571 (do ((i 1 (+ i 1)))
572 ((> i *expint-maxit*)
573 (merror (intl:gettext "expintegral_e: series failed.")))
574 (setq f (* -1 f (/ z i)))
575 (cond
576 ((= i n1)
577 (let ((psi (- euler)))
578 (dotimes (ii n1)
579 (setq psi (+ psi (/ 1.0 (+ ii 1)))))
580 (setq e (* f (- psi (log z))))))
582 (setq e (/ (- f) (- i n1)))))
583 (setq r (+ r e))
584 (when (< (abs e) (* (abs r) *expint-eps*))
585 (when *debug-expintegral*
586 (setq *debug-expint-maxit* (max *debug-expint-maxit* i)))
587 (return r))))))))
589 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
590 ;;; Numerical evaluation for a real or complex parameter.
591 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
593 (defun frac-expintegral-e (n z)
594 (declare (type (complex flonum) n)
595 (type (complex flonum) z))
597 (let ((*expint-eps* *expint-eps*)
598 (*expint-maxit* *expint-maxit*))
600 (when *debug-expintegral*
601 (format t "~&FRAC-EXPINTEGRAL-E called with:~%")
602 (format t "~& : n = ~A~%" n)
603 (format t "~& : z = ~A~%" z))
605 (cond
606 ((and (> (realpart z) 0) (> (abs z) 1.0))
607 ;; We expand in continued fractions.
608 (when *debug-expintegral*
609 (format t "~&We expand in continued fractions.~%"))
610 (let* ((b (+ z n))
611 (c (/ 1.0 (* *expint-eps* *expint-eps*)))
612 (d (/ 1.0 b))
613 (n1 (- n 1))
614 (h d)
615 (e 0.0))
616 (do* ((i 1 (+ i 1))
617 (a (* -1 n) (* (- i) (+ n1 i))))
618 ((> i *expint-maxit*)
619 (merror
620 (intl:gettext "expintegral_e: continued fractions failed.")))
622 (setq b (+ b 2.0))
623 (setq d (/ 1.0 (+ (* a d) b)))
624 (setq c (+ b (/ a c)))
625 (setq e (* c d))
626 (setq h (* h e))
628 (when (< (abs (- e 1.0)) *expint-eps*)
629 (when *debug-expintegral*
630 (setq *debug-expint-fracmaxit* (max *debug-expint-fracmaxit* i)))
631 (return (* h (exp (- z))))))))
633 ((and (= (imagpart n) 0)
634 (> (realpart n) 0)
635 (= (nth-value 1 (truncate (realpart n))) 0))
636 ;; We have a positive integer n or an float representation of an
637 ;; integer. We call expintegral-e which does this calculation.
638 (when *debug-expintegral*
639 (format t "~&We call expintegral-e.~%"))
640 (expintegral-e (truncate (realpart n)) z))
643 ;; At this point the parameter n is a real (not an float representation
644 ;; of an integer) or complex. We expand in a power series.
645 (when *debug-expintegral*
646 (format t "~&We expand in a power series.~%"))
647 (let* ((n1 (- n 1))
648 ;; It would be possible to call the numerical implementation
649 ;; gamm-lanczos directly. But then the code would depend on the
650 ;; details of the implementation.
651 (gm (let ((tmp (take '(%gamma) (complexify (- 1 n)))))
652 (complex ($realpart tmp) ($imagpart tmp))))
653 (r (- (* (expt z n1) gm) (/ 1.0 (- 1 n))))
654 (f 1.0)
655 (e 0.0))
656 (do ((i 1 (+ i 1)))
657 ((> i *expint-maxit*)
658 (merror (intl:gettext "expintegral_e: series failed.")))
659 (setq f (* -1 f (/ z (float i))))
660 (setq e (/ (- f) (- (float i) n1)))
661 (setq r (+ r e))
662 (when (< (abs e) (* (abs r) *expint-eps*))
663 (when *debug-expintegral*
664 (setq *debug-expint-fracmaxit* (max *debug-expint-fracmaxit* i)))
665 (return r))))))))
667 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
668 ;;; Helper functions for Bigfloat numerical evaluation.
669 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
671 (defun cmul (x y) ($rectform (mul x y)))
673 (defun cdiv (x y) ($rectform (div x y)))
675 (defun cpower (x y) ($rectform (power x y)))
677 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
678 ;;; We have not changed the above algorithm, but generalized it to handle
679 ;;; complex and real Bigfloat numbers. By carefully examination of the
680 ;;; algorithm some of the additional calls to $rectform can be eliminated.
681 ;;; But the algorithm works and so we leave the extra calls for later work
682 ;;; in the code.
683 ;;; The accuracy of the result is determined by *expint-eps*. The value is
684 ;;; chosen to correspond to the value of $fpprec. We don't give any extra
685 ;;; digits to fpprec, so we loose 1 to 2 digits of precision.
686 ;;; One problem is to chose a sufficient big *expint-maxit*.
687 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
689 (defun bfloat-expintegral-e (n z)
690 (let ((*expint-eps* (power ($bfloat 10.0) (- $fpprec)))
691 (*expint-maxit* 5000) ; arbitrarily chosen, we need a better choice
692 (bigfloattwo (add bigfloatone bigfloatone))
693 (bigfloat%e ($bfloat '$%e))
694 (bigfloat%gamma ($bfloat '$%gamma))
695 (flz (complex ($float ($realpart z)) ($float ($imagpart z)))))
697 (when *debug-expintegral*
698 (format t "~&BFLOAT-EXPINTEGRAL-E called with:~%")
699 (format t "~& : n = ~A~%" n)
700 (format t "~& : z = ~A~%" flz))
702 (cond
703 ((or (and (> (abs flz) 2) (< (abs (phase flz)) (* pi 0.9)))
704 ;; The same condition as you see in expintegral-e()
705 (and (>= (realpart flz) 0) (> (abs flz) 1.0)))
706 ;; We expand in continued fractions.
707 (when *debug-expintegral*
708 (format t "~&We expand in continued fractions.~%"))
709 (let* ((b (add z n))
710 (c (div bigfloatone (mul *expint-eps* *expint-eps*)))
711 (d (cdiv bigfloatone b))
712 (n1 (- n 1))
713 (h d)
714 (e 0.0))
715 (do* ((i 1 (+ i 1))
716 (a (* -1 n) (* (- i) (+ n1 i))))
717 ((> i *expint-maxit*)
718 (merror
719 (intl:gettext "expintegral_e: continued fractions failed.")))
721 (setq b (add b bigfloattwo))
722 (setq d (cdiv bigfloatone (add (mul a d) b)))
723 (setq c (add b (cdiv a c)))
724 (setq e (cmul c d))
725 (setq h (cmul h e))
727 (when (eq ($sign (sub (cabs (sub e bigfloatone)) *expint-eps*))
728 '$neg)
729 (when *debug-expintegral*
730 (setq *debug-expint-bfloatmaxit*
731 (max *debug-expint-bfloatmaxit* i)))
732 (return (cmul h (cpower bigfloat%e (mul -1 z))))))))
734 ;; We expand in a power series.
735 (when *debug-expintegral*
736 (format t "~&We expand in a power series.~%"))
737 (let* ((n1 (- n 1))
738 (meuler (mul -1 bigfloat%gamma))
739 (r (if (= n1 0) (sub meuler ($log z)) (div bigfloatone n1)))
740 (f bigfloatone)
741 (e bigfloatzero))
742 (do* ((i 1 (+ i 1)))
743 ((> i *expint-maxit*)
744 (merror (intl:gettext "expintegral_e: series failed.")))
745 (setq f (mul -1 (cmul f (cdiv z i))))
746 (cond
747 ((= i n1)
748 (let ((psi meuler))
749 (dotimes (ii n1)
750 (setq psi (add psi (cdiv bigfloatone (+ ii 1)))))
751 (setq e (cmul f (sub psi ($log z))))))
753 (setq e (cdiv (mul -1 f) (- i n1)))))
754 (setq r (add r e))
755 (when (eq ($sign (sub (cabs e) (cmul (cabs r) *expint-eps*)))
756 '$neg)
757 (when *debug-expintegral*
758 (setq *debug-expint-bfloatmaxit*
759 (max *debug-expint-bfloatmaxit* i)))
760 (return r))))))))
762 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
763 ;;; Numerical Bigfloat evaluation for a real (Bigfloat) parameter.
764 ;;; The algorithm would work for a Complex Bigfloat parameter too. But we
765 ;;; need the values of Gamma for Complex Bigfloats. This is at this time (2008)
766 ;;; not implemented in Maxima.
767 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
769 (defun frac-bfloat-expintegral-e (n z)
770 (let ((*expint-eps* (power ($bfloat 10.0) (- $fpprec)))
771 (*expint-maxit* 5000) ; arbitrarily chosen, we need a better choice
772 (bigfloattwo (add bigfloatone bigfloatone))
773 (bigfloat%e ($bfloat '$%e))
774 (bigfloat%gamma ($bfloat '$%gamma)))
776 (when *debug-expintegral*
777 (format t "~&FRAC-BFLOAT-EXPINTEGRAL-E called with:~%")
778 (format t "~& : n = ~A~%" n)
779 (format t "~& : z = ~A~%" z))
781 (cond
782 ((and (or (eq ($sign ($realpart z)) '$pos)
783 (eq ($sign ($realpart z)) '$zero))
784 (eq ($sign (sub (cabs z) bigfloatone)) '$pos))
785 ;; We expand in continued fractions.
786 (when *debug-expintegral*
787 (format t "We expand in continued fractions.~%"))
788 (let* ((b (add z n))
789 (c (div bigfloatone (mul *expint-eps* *expint-eps*)))
790 (d (cdiv bigfloatone b))
791 (n1 (sub n 1))
792 (h d)
793 (e 0.0))
794 (do* ((i 1 (+ i 1))
795 (a (mul -1 n) (cmul (- i) (add n1 i))))
796 ((> i *expint-maxit*)
797 (merror
798 (intl:gettext "expintegral_e: continued fractions failed.")))
800 (setq b (add b bigfloattwo))
801 (setq d (cdiv bigfloatone (add (mul a d) b)))
802 (setq c (add b (cdiv a c)))
803 (setq e (cmul c d))
804 (setq h (cmul h e))
806 (when (eq ($sign (sub (cabs (sub e bigfloatone)) *expint-eps*))
807 '$neg)
808 (when *debug-expintegral*
809 (setq *debug-expint-fracbfloatmaxit*
810 (max *debug-expint-fracbfloatmaxit* i)))
811 (return (cmul h (cpower bigfloat%e (mul -1 z))))))))
813 ((or (and (numberp n)
814 (= ($imagpart n) 0)
815 (> ($realpart n) 0)
816 (= (nth-value 1 (truncate ($realpart n))) 0))
817 (and ($bfloatp n)
818 (eq ($sign n) '$pos)
819 (equal (sub (mul 2 ($fix n)) (mul 2 n))
820 bigfloatzero)))
821 ;; We have a Float or Bigfloat representation of positive integer.
822 ;; We call bfloat-expintegral-e.
823 (when *debug-expintegral*
824 (format t "frac-Bigfloat with integer ~A~%" n))
825 (bfloat-expintegral-e ($fix ($realpart n)) z))
828 ;; At this point the parameter n is a real (not a float representation
829 ;; of an integer) or complex. We expand in a power series.
830 (when *debug-expintegral*
831 (format t "We expand in a power series.~%"))
832 (let* ((n1 (sub n bigfloatone))
833 (n2 (sub bigfloatone n))
834 (gm (take '(%gamma) n2))
835 (r (sub (cmul (cpower z n1) gm) (cdiv bigfloatone n2)))
836 (f bigfloatone)
837 (e bigfloatzero))
838 (do ((i 1 (+ i 1)))
839 ((> i *expint-maxit*)
840 (merror (intl:gettext "expintegral_e: series failed.")))
841 (setq f (cmul (mul -1 bigfloatone) (cmul f (cdiv z i))))
842 (setq e (cdiv (mul -1 f) (sub i n1)))
843 (setq r (add r e))
844 (when (eq ($sign (sub (cabs e) (cmul (cabs r) *expint-eps*)))
845 '$neg)
846 (when *debug-expintegral*
847 (setq *debug-expint-fracbfloatmaxit*
848 (max *debug-expint-fracbfloatmaxit* i)))
849 (return r))))))))
851 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
853 ;;; Part 2: The implementation of the Exponential Integral E1
855 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
857 ;;; Exponential Integral E1 distributes over bags
859 (defprop %expintegral_e1 (mlist $matrix mequal) distribute_over)
861 ;;; Exponential Integral E1 has mirror symmetry,
862 ;;; but not on the real negative axis.
864 (defprop %expintegral_e1 conjugate-expintegral-e1 conjugate-function)
866 (defun conjugate-expintegral-e1 (args)
867 (let ((z (first args)))
868 (cond ((off-negative-real-axisp z)
869 ;; Definitely not on the negative real axis for z. Mirror symmetry.
870 (take '(%expintegral_e1) (take '($conjugate) z)))
872 ;; On the negative real axis or no information. Unsimplified.
873 (list '($conjugate simp) (take '(%expintegral_e1) z))))))
875 ;;; Differentiation of Exponential Integral E1
877 (defprop %expintegral_e1
878 ((x)
879 ((mtimes) -1
880 ((mexpt) x -1)
881 ((mexpt) $%e ((mtimes) -1 x))))
882 grad)
884 ;;; Integral of Exponential Integral E1
886 (defprop %expintegral_e1
887 ((z)
888 ((mtimes) -1 ((%expintegral_e) 2 z)))
889 integral)
891 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
893 ;;; We support a simplim%function. The function is looked up in simplimit and
894 ;;; handles specific values of the function.
896 (defprop %expintegral_e1 simplim%expintegral_e1 simplim%function)
898 (defun simplim%expintegral_e1 (expr var val)
899 ;; Look for the limit of the argument.
900 (let ((z (limit (cadr expr) var val 'think)))
901 (cond
902 ;; Handle an argument 0 at this place
903 ((or (zerop1 z)
904 (eq z '$zeroa)
905 (eq z '$zerob))
906 ;; limit is inf from both sides
907 '$inf)
909 ;; All other cases are handled by the simplifier of the function.
910 (take '(%expintegral_e1) z)))))
912 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
914 ;;; Exponential Integral E1 is a simplifying function
915 (def-simplifier expintegral_e1 (arg)
916 (cond
917 ;; Check for special values
918 ((or (eq arg '$inf)
919 (alike1 arg '((mtimes) -1 $minf)))
921 ((zerop1 arg)
922 (simp-domain-error
923 (intl:gettext "expintegral_e1: expintegral_e1(~:M) is undefined.") arg))
925 ;; Check for numerical evaluation
926 ((complex-float-numerical-eval-p arg)
927 ;; For E1 we call En(z) with n=1 directly.
928 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
929 (complexify (expintegral-e 1 carg))))
931 ((complex-bigfloat-numerical-eval-p arg)
932 ;; For E1 we call En(z) with n=1 directly.
933 (let* (($ratprint nil)
934 (carg (add ($bfloat ($realpart arg))
935 (mul '$%i ($bfloat ($imagpart arg)))))
936 (result (bfloat-expintegral-e 1 carg)))
937 (add ($realpart result)
938 (mul '$%i ($imagpart result)))))
940 ;; Check argument simplifications and transformations
941 ((taylorize (mop form) (second form)))
943 ((and $expintrep
944 (member $expintrep *expintflag* :test #'eq)
945 (not (eq $expintrep '%expintegral_e1)))
946 (case $expintrep
947 (%gamma_incomplete
948 (take '(%gamma_incomplete) 0 arg))
949 (%expintegral_ei
950 (add (mul -1 (take '(%expintegral_ei) (mul -1 arg)))
951 (mul (inv 2)
952 (sub (take '(%log) (mul -1 arg))
953 (take '(%log) (mul -1 (inv arg)))))
954 (mul -1 (take '(%log) arg))))
955 (%expintegral_li
956 (add (mul -1 (take '(%expintegral_li) (power '$%e (mul -1 arg))))
957 (mul -1 (take '(%log) arg))
958 (mul (inv 2)
959 (sub (take '(%log) (mul -1 arg))
960 (take '(%log) (mul -1 (inv arg)))))))
961 ($expintegral_trig
962 (add (mul -1 '$%i (take '(%expintegral_si) (mul '$%i arg)))
963 (mul -1 (take '(%expintegral_ci) (mul '$%i arg)))
964 (take '(%log) (mul '$%i arg))
965 (mul -1 (take '(%log) arg))))
966 ($expintegral_hyp
967 (sub (take '(%expintegral_shi) arg)
968 (take '(%expintegral_chi) arg)))
970 (give-up))))
973 (give-up))))
975 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
977 ;;; Part 3: The implementation of the Exponential Integral Ei
979 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
981 ;;; Exponential Integral Ei distributes over bags
983 (defprop %expintegral_ei (mlist $matrix mequal) distribute_over)
985 ;;; Exponential Integral Ei has mirror symmetry
987 (defprop %expintegral_ei t commutes-with-conjugate)
989 ;;; Differentiation of Exponential Integral Ei
991 (defprop %expintegral_ei
992 ((x)
993 ((mtimes) ((mexpt) x -1) ((mexpt) $%e x)))
994 grad)
996 ;;; Integral of Exponential Ei
998 (defprop %expintegral_ei
999 ((x)
1000 ((mplus)
1001 ((mtimes) -1 ((mexpt) $%e x))
1002 ((mtimes) x ((%expintegral_ei) x))))
1003 integral)
1005 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1007 ;;; We support a simplim%function. The function is looked up in simplimit and
1008 ;;; handles specific values of the function.
1010 (defprop %expintegral_ei simplim%expintegral_ei simplim%function)
1012 (defun simplim%expintegral_ei (expr var val)
1013 ;; Look for the limit of the arguments.
1014 (let ((z (limit (cadr expr) var val 'think)))
1015 (cond
1016 ;; Handle an argument 0 at this place
1017 ((or (zerop1 z)
1018 (eq z '$zeroa)
1019 (eq z '$zerob))
1020 '$minf)
1022 ;; All other cases are handled by the simplifier of the function.
1023 (take '(%expintegral_ei) z)))))
1025 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1027 ;;; Exponential Integral Ei is a simplifying function
1028 (def-simplifier expintegral_ei (arg)
1029 (cond
1030 ;; Check special values
1031 ((zerop1 arg)
1032 (simp-domain-error
1033 (intl:gettext "expintegral_ei: expintegral_ei(~:M) is undefined.")
1034 arg))
1035 ((or (eq arg '$inf)
1036 (alike1 arg '((mtimes) -1 $minf)))
1037 '$inf)
1038 ((or (eq arg '$minf)
1039 (alike1 arg '((mtimes) -1 $inf)))
1041 ((or (alike1 arg '((mtimes) $%i $inf))
1042 (alike1 arg '((mtimes) -1 $%i $minf)))
1043 (mul '$%i '$%pi))
1044 ((or (alike1 arg '((mtimes) $%i $minf))
1045 (alike1 arg '((mtimes) -1 $%i $inf)))
1046 (mul -1 '$%i '$%pi))
1048 ;; Check numerical evaluation
1049 ((complex-float-numerical-eval-p arg)
1050 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1051 (complexify (expintegral-ei carg))))
1053 ((complex-bigfloat-numerical-eval-p arg)
1054 (let* (($ratprint nil)
1055 (carg (add ($bfloat ($realpart arg))
1056 (mul '$%i ($bfloat ($imagpart arg)))))
1057 (result (bfloat-expintegral-ei carg)))
1058 (add ($realpart result)
1059 (mul '$%i ($imagpart result)))))
1061 ;; Check argument simplifications and transformations
1062 ((taylorize (mop form) (second form)))
1064 ((and $expintrep
1065 (member $expintrep *expintflag*)
1066 (not (eq $expintrep '%expintegral_ei)))
1067 (case $expintrep
1068 (%gamma_incomplete
1069 (add (mul -1 (take '(%gamma_incomplete) 0 (mul -1 arg)))
1070 (mul (inv 2)
1071 (sub (take '(%log) arg)
1072 (take '(%log) (inv arg))))
1073 (mul -1 (take '(%log) (mul -1 arg)))))
1074 (%expintegral_e1
1075 (add (mul -1 (take '(%expintegral_e1) (mul -1 arg)))
1076 (mul (inv 2)
1077 (sub (take '(%log) arg)
1078 (take '(%log) (inv arg))))
1079 (mul -1 (take '(%log) (mul -1 arg)))))
1080 (%expintegral_li
1081 (take '(%expintegral_li) (power '$%e arg)))
1082 ($expintegral_trig
1083 (add (take '(%expintegral_ci) (mul '$%i arg))
1084 (mul -1 '$%i (take '(%expintegral_si) (mul '$%i arg)))
1085 (mul (inv -2)
1086 (sub (take '(%log) (inv arg))
1087 (take '(%log) arg)))
1088 (mul -1 (take '(%log) (mul '$%i arg)))))
1089 ($expintegral_hyp
1090 (add (take '(%expintegral_chi) arg)
1091 (take '(%expintegral_shi) arg)
1092 (mul (inv -2)
1093 (add (take '(%log) (inv arg))
1094 (take '(%log) arg)))))))
1096 ($hypergeometric_representation
1097 ;; See http://functions.wolfram.com/06.35.26.0001.01
1099 ;; expintegral_ei(z) = z*hypergeometric([1,1],[2,2],z)
1100 ;; + 1/2*(log(z) - log(1/z)) + %gamma
1102 ;; But note that Maxima expands log(1/z) to -log(z), but this is
1103 ;; not true when z is on the negative real axis. log(-1/2) =
1104 ;; -log(2) + %i*%pi, but log(-2) = log(2) + %i*%pi. Hence,
1105 ;; log(-1/2) is not -log(2).
1106 (add (mul arg
1107 (ftake '%hypergeometric
1108 (make-mlist 1 1)
1109 (make-mlist 2 2)
1110 arg))
1111 (mul 1//2
1112 (sub (ftake '%log arg)
1113 (ftake '%log (div 1 arg))))
1114 '$%gamma))
1116 (give-up))))
1118 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1119 ;;; Numerical evaluation of the Exponential Integral Ei(z):
1121 ;;; We use the following representation (see functions.wolfram.com):
1123 ;;; Ei(z) = -E1(-z) + 0.5*(log(z)-log(1/z))-log(-z)
1125 ;;; z is a CL Complex number. Because we evaluate for Complex values we have to
1126 ;;; take into account the complete Complex phase factors.
1127 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1129 (defun expintegral-ei (z)
1130 (+ (- (expintegral-e 1 (- z)))
1131 ;; Carefully compute 1/2*(log(z)-log(1/z))-log(-z), using the
1132 ;; branch cuts that we want, not the one that Lisp wants.
1133 ;; (Mostly an issue with Lisps that support signed zeroes.)
1134 (cond
1135 ((> (imagpart z) 0)
1136 ;; Positive imaginary part. Add phase %i*%pi.
1137 (complex 0 (float pi)))
1138 ((< (imagpart z) 0)
1139 ;; Negative imaginary part. Add phase -%i*%pi.
1140 (complex 0 (- (float pi))))
1141 ((> (realpart z) 0)
1142 ;; Positive real value. Add phase -%i*pi.
1143 (complex 0 (- (float pi))))
1144 ;; Negative real value. No phase factor.
1145 (t 0))))
1147 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1148 ;;; We have not modified the algorithm for Bigfloat numbers. It is only
1149 ;;; generalized for Bigfloats. The calcualtion of the complex phase factor
1150 ;;; can be simplified to conditions about the sign of the realpart and
1151 ;;; imagpart. We leave this for further work to optimize the speed of the
1152 ;;; calculation.
1153 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1155 (defun bfloat-expintegral-ei (z)
1156 (let ((mz (mul -1 z)))
1157 (add (cmul (mul -1 bigfloatone)
1158 (bfloat-expintegral-e 1 mz))
1159 (sub (cmul (div bigfloatone 2)
1160 (sub (take '(%log) z)
1161 (take '(%log) (cdiv bigfloatone z))))
1162 (take '(%log) mz)))))
1164 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1166 ;;; Part 4: The implementation of the Logarithmic integral li(z)
1168 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1170 ;;; Exponential Integral Li distributes over bags
1172 (defprop %expintegral_li (mlist $matrix mequal) distribute_over)
1174 ;;; Exponential Integral Li has mirror symmetry,
1175 ;;; but not on the real negative axis.
1177 (defprop %expintegral_li conjugate-expintegral-li conjugate-function)
1179 (defun conjugate-expintegral-li (args)
1180 (let ((z (first args)))
1181 (cond ((off-negative-real-axisp z)
1182 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1183 (take '(%expintegral_li) (take '($conjugate) z)))
1185 ;; On the negative real axis or no information. Unsimplified.
1186 (list '($conjugate simp) (take '(%expintegral_li) z))))))
1188 ;;; Differentiation of Exponential Integral Li
1190 (defprop %expintegral_li
1191 ((x)
1192 ((mtimes) ((mexpt) ((%log) x) -1)))
1193 grad)
1195 ;;; Integral of Exponential Li
1197 (defprop %expintegral_li
1198 ((x)
1199 ((mplus)
1200 ((mtimes) x ((%expintegral_li) x))
1201 ((mtimes) -1 ((%expintegral_ei) ((mtimes) 2 ((%log) x))))))
1202 integral)
1204 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1206 ;;; We support a simplim%function. The function is looked up in simplimit and
1207 ;;; handles specific values of the function.
1209 (defprop %expintegral_li simplim%expintegral_li simplim%function)
1211 (defun simplim%expintegral_li (expr var val)
1212 ;; Look for the limit of the argument.
1213 (let ((z (limit (cadr expr) var val 'think)))
1214 (cond
1215 ;; Handle an argument 1 at this place
1216 ((onep1 z) '$minf)
1218 ;; All other cases are handled by the simplifier of the function.
1219 (take '(%expintegral_li) z)))))
1221 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1223 ;;; Exponential Integral Li is a simplifying function
1224 (def-simplifier expintegral_li (arg)
1225 (cond
1226 ((zerop1 arg) arg)
1227 ((onep1 arg)
1228 (simp-domain-error
1229 (intl:gettext "expintegral_li: expintegral_li(~:M) is undefined.") arg))
1230 ((or (eq arg '$inf)
1231 (alike1 arg '((mtimes) -1 $minf)))
1232 '$inf)
1233 ((eq arg '$infinity) '$infinity)
1235 ((complex-float-numerical-eval-p arg)
1236 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1237 (complexify (expintegral-li carg))))
1239 ((complex-bigfloat-numerical-eval-p arg)
1240 (let* (($ratprint nil)
1241 (carg (add ($bfloat ($realpart arg))
1242 (mul '$%i ($bfloat ($imagpart arg)))))
1243 (result (bfloat-expintegral-li carg)))
1244 (add (mul '$%i ($imagpart result))
1245 ($realpart result))))
1247 ;; Check for argument simplifications and transformations
1248 ((taylorize (mop form) (second form)))
1250 ((and $expintrep
1251 (member $expintrep *expintflag*)
1252 (not (eq $expintrep '%expintegral_li)))
1253 (let ((logarg (take '(%log) arg)))
1254 (case $expintrep
1255 (%gamma_incomplete
1256 (add (mul -1 (take '(%gamma_incomplete) 0 (mul -1 logarg)))
1257 (mul (inv 2)
1258 (sub (take '(%log) logarg)
1259 (take '(%log) (inv logarg))))
1260 (mul -1 (take '(%log) (mul -1 logarg)))))
1261 (%expintegral_e1
1262 (add (mul -1 (take '(%expintegral_e1) (mul -1 logarg)))
1263 (mul (inv 2)
1264 (sub (take '(%log) logarg)
1265 (take '(%log) (inv logarg))))
1266 (mul -1 (take '(%log) (mul -1 logarg)))))
1267 (%expintegral_ei
1268 (take '(%expintegral_ei) logarg))
1269 ($expintegral_trig
1270 (add (take '(%expintegral_ci) (mul '$%i logarg))
1271 (mul -1 '$%i (take '(%expintegral_si) (mul '$%i logarg)))
1272 (mul (inv -2)
1273 (sub (take '(%log) (inv logarg))
1274 (take '(%log) logarg)))
1275 (mul -1 (take '(%log) (mul '$%i logarg)))))
1276 ($expintegral_hyp
1277 (add (take '(%expintegral_chi) logarg)
1278 (take '(%expintegral_shi) logarg)
1279 (mul (inv -2)
1280 (add (take '(%log) (inv logarg))
1281 (take '(%log) logarg))))))))
1282 ($hypergeometric_representation
1283 ;; See http://functions.wolfram.com/06.36.26.0001.01
1285 ;; expintegral_li(z) = log(z)*hypergeometric([1,1],[2,2],log(z))
1286 ;; + 1/2*(log(log(z)) - log(1/log(z))) + %gamma
1288 ;; But note that Maxima expands log(1/z) to -log(z), but this is
1289 ;; not true when z is on the negative real axis. log(-1/2) =
1290 ;; -log(2) + %i*%pi, but log(-2) = log(2) + %i*%pi. Hence,
1291 ;; log(-1/2) is not -log(2).
1292 (add (mul (ftake '%log arg)
1293 (ftake '%hypergeometric
1294 (make-mlist 1 1)
1295 (make-mlist 2 2)
1296 (ftake '%log arg)))
1297 (mul 1//2
1298 (sub (ftake '%log (ftake '%log arg))
1299 (ftake '%log (div 1 (ftake '%log arg)))))
1300 '$%gamma))
1302 (give-up))))
1304 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1305 ;;; Numerical evaluation of the Expintegral Li
1307 ;;; We use the representation:
1309 ;;; Li(z) = Ei(log(z))
1310 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1312 (defun expintegral-li (z)
1313 (expintegral-ei (log z)))
1315 (defun bfloat-expintegral-li (z)
1316 (bfloat-expintegral-ei ($log z)))
1318 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1320 ;;; Part 5: The implementation of the Exponential Integral Si
1322 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1324 ;;; Exponential Integral Si distributes over bags
1326 (defprop %expintegral_si (mlist $matrix mequal) distribute_over)
1328 ;;; Exponential Integral Si has mirror symmetry
1330 (defprop %expintegral_si t commutes-with-conjugate)
1332 ;;; Exponential Integral Si is a odd function
1334 (defprop %expintegral_si odd-function-reflect reflection-rule)
1336 ;;; Differentiation of Exponential Integral Si
1338 (defprop %expintegral_si
1339 ((x)
1340 ((mtimes) ((%sin) x) ((mexpt) x -1)))
1341 grad)
1343 ;;; Integral of Exponential Si
1345 (defprop %expintegral_si
1346 ((x)
1347 ((mplus)
1348 ((%cos) x)
1349 ((mtimes) x ((%expintegral_si) x))))
1350 integral)
1352 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1354 ;;; We support a simplim%function.
1356 (defprop %expintegral_si simplim%expintegral_si simplim%function)
1358 (defun simplim%expintegral_si (expr var val)
1359 ;; Look for the limit of the argument.
1360 (let ((z (limit (cadr expr) var val 'think)))
1361 ;; All cases are handled by the simplifier of the function.
1362 (take '(%expintegral_si) z)))
1364 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1366 ;;; Exponential Integral Si is a simplifying function
1367 (def-simplifier expintegral_si (arg)
1368 (cond
1369 ;; Check for special values
1370 ((zerop1 arg) arg)
1371 ((or (eq arg '$inf)
1372 (alike1 arg '((mtimes) -1 $minf)))
1373 (div '$%pi 2))
1374 ((or (eq arg '$minf)
1375 (alike1 arg '((mtimes) -1 $inf)))
1376 (mul -1 (div '$%pi 2)))
1378 ;; Check for numerical evaluation
1379 ((complex-float-numerical-eval-p arg)
1380 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1381 (complexify (expintegral-si carg))))
1383 ((complex-bigfloat-numerical-eval-p arg)
1384 (let* (($ratprint nil)
1385 (carg (add ($bfloat ($realpart arg))
1386 (mul '$%i ($bfloat ($imagpart arg)))))
1387 (result (bfloat-expintegral-si carg)))
1388 (add (mul '$%i ($imagpart result))
1389 ($realpart result))))
1391 ;; Check for argument simplifications and transformations
1392 ((taylorize (mop form) (second form)))
1393 ((apply-reflection-simp (mop form) arg $trigsign))
1395 ((and $expintrep
1396 (member $expintrep *expintflag*)
1397 (not (eq $expintrep '$expintegral_trig)))
1398 (case $expintrep
1399 (%gamma_incomplete
1400 (mul (div '$%i 2)
1401 (add (take '(%gamma_incomplete) 0 (mul -1 '$%i arg))
1402 (mul -1 (take '(%gamma_incomplete) 0 (mul '$%i arg)))
1403 (take '(%log) (mul -1 '$%i arg))
1404 (mul -1 (take '(%log) (mul '$%i arg))))))
1405 (%expintegral_e1
1406 (mul (div '$%i 2)
1407 (add (take '(%expintegral_e1) (mul -1 '$%i arg))
1408 (mul -1 (take '(%expintegral_e1) (mul '$%i arg)))
1409 (take '(%log) (mul -1 '$%i arg))
1410 (mul -1 (take '(%log) (mul '$%i arg))))))
1411 (%expintegral_ei
1412 (mul (div '$%i 4)
1413 (add (mul 2
1414 (sub (take '(%expintegral_ei) (mul -1 '$%i arg))
1415 (take '(%expintegral_ei) (mul '$%i arg))))
1416 (take '(%log) (div '$%i arg))
1417 (mul -1 (take '(%log) (mul -1 (div '$%i arg))))
1418 (mul -1 (take '(%log) (mul -1 '$%i arg)))
1419 (take '(%log) (mul '$%i arg)))))
1420 (%expintegral_li
1421 (mul (inv (mul 2 '$%i))
1422 (add (take '(%expintegral_li) (power '$%e (mul '$%i arg)))
1423 (mul -1
1424 (take '(%expintegral_li)
1425 (power '$%e (mul -1 '$%e arg))))
1426 (mul (div '$%pi -2)
1427 (take '(%signum) ($realpart arg))))))
1428 ($expintegral_hyp
1429 (mul -1 '$%i (take '(%expintegral_shi) (mul '$%i arg))))))
1431 ($hypergeometric_representation
1432 ;; See http://functions.wolfram.com/06.37.26.0001.01
1434 ;; expintegral_si(z) = z*hypergeometric([1/2],[3/2,3/2],-z^2/4)
1436 (mul arg
1437 (ftake '%hypergeometric
1438 (make-mlist 1//2)
1439 (make-mlist 3//2 3//2)
1440 (div (mul arg arg)
1441 -4))))
1443 (give-up))))
1445 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1446 ;;; Numerical evaluation of the Exponential Integral Si
1448 ;;; We use the representation:
1450 ;;; Si(z) = %i/2 * (E1(-%i*z) - E1(*%i*z) + log(%i*z) - log(-%i*z))
1452 ;;; For the Sin, Cos, Sinh and Cosh Exponential Integrals we have to call the
1453 ;;; numerical evaluation twice. In principle we could use a direct expansion
1454 ;;; in a power series or continued fractions to optimize the speed of the code.
1455 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1457 (defun expintegral-si (z)
1458 (let ((z (coerce z '(complex flonum))))
1459 (* (complex 0 0.5)
1460 (+ (expintegral-e 1 (* (complex 0 -1) z))
1461 (- (expintegral-e 1 (* (complex 0 1) z)))
1462 (log (* (complex 0 -1) z))
1463 (- (log (* (complex 0 1) z)))))))
1465 (defun bfloat-expintegral-si (z)
1466 (let ((z*%i (cmul '$%i z))
1467 (mz*%i (cmul (mul -1 '$%i) z)))
1468 (cmul
1469 (mul 0.5 '$%i)
1470 (add
1471 (bfloat-expintegral-e 1 mz*%i)
1472 (mul -1 (bfloat-expintegral-e 1 z*%i))
1473 ($log mz*%i)
1474 (mul -1 ($log z*%i))))))
1476 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1478 ;;; Part 6: The implementation of the Exponential Integral Shi
1480 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1482 ;;; Exponential Integral Shi distributes over bags
1484 (defprop %expintegral_shi (mlist $matrix mequal) distribute_over)
1486 ;;; Exponential Integral Shi has mirror symmetry
1488 (defprop %expintegral_si t commutes-with-conjugate)
1490 ;;; Exponential Integral Shi is a odd function
1492 (defprop %expintegral_si odd-function-reflect reflection-rule)
1494 ;;; Differentiation of Exponential Integral Shi
1496 (defprop %expintegral_shi
1497 ((x)
1498 ((mtimes) ((%sinh) x) ((mexpt) x -1)))
1499 grad)
1501 ;;; Integral of Exponential Shi
1503 (defprop %expintegral_shi
1504 ((x)
1505 ((mplus)
1506 ((mtimes) -1 ((%cosh) x))
1507 ((mtimes) x ((%expintegral_shi) x))))
1508 integral)
1510 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1512 ;;; We support a simplim%function. The function is looked up in simplimit and
1513 ;;; handles specific values of the function.
1515 (defprop %expintegral_shi simplim%expintegral_shi simplim%function)
1517 (defun simplim%expintegral_shi (expr var val)
1518 ;; Look for the limit of the argument.
1519 (let ((z (limit (cadr expr) var val 'think)))
1520 (cond
1521 ;; Handle infinities at this place
1522 ((eq z '$inf)
1523 '$inf)
1524 ((eq z '$minf)
1525 '$minf)
1527 ;; All other cases are handled by the simplifier of the function.
1528 (take '(%expintegral_shi) z)))))
1530 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1532 ;;; Exponential Integral Shi is a simplifying function
1533 (def-simplifier expintegral_shi (arg)
1534 (cond
1535 ;; Check for special values
1536 ((zerop1 arg) arg)
1537 ((or (alike1 arg '((mtimes) $%i $inf))
1538 (alike1 arg '((mtimes) -1 $%i $minf)))
1539 (div (mul '$%i '$%pi) 2))
1540 ((or (alike1 arg '((mtimes) $%i $minf))
1541 (alike1 arg '((mtimes) -1 $%i $inf)))
1542 (div (mul -1 '$%i '$%pi) 2))
1544 ;; Check for numrical evaluation
1545 ((float-numerical-eval-p arg)
1546 (realpart (expintegral-shi arg)))
1548 ((complex-float-numerical-eval-p arg)
1549 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1550 (complexify (expintegral-shi carg))))
1552 ((complex-bigfloat-numerical-eval-p arg)
1553 (let* (($ratprint nil)
1554 (carg (add ($bfloat ($realpart arg))
1555 (mul '$%i ($bfloat ($imagpart arg)))))
1556 (result (bfloat-expintegral-shi carg)))
1557 (add (mul '$%i ($imagpart result))
1558 ($realpart result))))
1560 ;; Check for argument simplifications and transformations
1561 ((taylorize (mop form) (second form)))
1562 ((apply-reflection-simp (mop form) arg $trigsign))
1564 ((and $expintrep
1565 (member $expintrep *expintflag*)
1566 (not (eq $expintrep '$expintegral_hyp)))
1567 (case $expintrep
1568 (%gamma_incomplete
1569 (mul (inv 2)
1570 (add (take '(%gamma_incomplete) 0 arg)
1571 (mul -1 (take '(%gamma_incomplete) 0 (mul -1 arg)))
1572 (mul -1 (take '(%log) (mul -1 arg)))
1573 (take '(%log) arg))))
1574 (%expintegral_e1
1575 (mul (inv 2)
1576 (add (take '(%expintegral_e1) arg)
1577 (mul -1 (take '(%expintegral_e1) (mul -1 arg)))
1578 (mul -1 (take '(%log) (mul -1 arg)))
1579 (take '(%log) arg))))
1580 (%expintegral_ei
1581 (mul (inv 4)
1582 (add (mul 2
1583 (sub (take '(%expintegral_ei) arg)
1584 (take '(%expintegral_ei) (mul -1 arg))))
1585 (take '(%log) (inv arg))
1586 (mul -1 (take '(%log) (mul -1 (inv arg))))
1587 (take '(%log) (mul -1 arg))
1588 (mul -1 (take '(%log) arg)))))
1589 (%expintegral_li
1590 (add (mul (inv 2)
1591 (sub (take '(%expintegral_li) (power '$%e arg))
1592 (take '(%expintegral_li) (power '$%e (mul -1 arg)))))
1593 (mul (div (mul '$%i '$%pi) -2)
1594 (take '(%signum) ($imagpart arg)))))
1595 ($expintegral_trig
1596 (mul -1 '$%i (take '(%expintegral_si) (mul '$%i arg))))))
1598 ($hypergeometric_representation
1599 ;; See http://functions.wolfram.com/06.39.26.0001.01
1601 ;; expintegral_shi(z) = z*hypergeometric([1/2],[3/2,3/2],z^2/4)
1603 (mul arg
1604 (ftake '%hypergeometric
1605 (make-mlist 1//2)
1606 (make-mlist 3//2 3//2)
1607 (div (mul arg arg)
1608 4))))
1610 (give-up))))
1612 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1613 ;;; Numerical evaluation of the Exponential Integral Shi
1615 ;;; We use the representation:
1617 ;;; Shi(z) = 1/2 * (E1(z) - E1(-z) - log(-z) + log(z))
1619 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1621 (defun expintegral-shi (z)
1625 (expintegral-e 1 z)
1626 (- (expintegral-e 1 (- z)))
1627 (- (log (- z)))
1628 (log z))))
1630 (defun bfloat-expintegral-shi (z)
1631 (let ((mz (mul -1 z)))
1632 (mul
1634 (add
1635 (bfloat-expintegral-e 1 z)
1636 (mul -1 (bfloat-expintegral-e 1 mz))
1637 (mul -1 ($log mz))
1638 ($log z)))))
1640 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1642 ;;; Part 7: The implementation of the Exponential Integral Ci
1644 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1646 ;;; Exponential Integral Ci distributes over bags
1648 (defprop %expintegral_ci (mlist $matrix mequal) distribute_over)
1650 ;;; Exponential Integral Ci has mirror symmetry,
1651 ;;; but not on the real negative axis.
1653 (defprop %expintegral_ci conjugate-expintegral-ci conjugate-function)
1655 (defun conjugate-expintegral-ci (args)
1656 (let ((z (first args)))
1657 (cond ((off-negative-real-axisp z)
1658 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1659 (take '(%expintegral_ci) (take '($conjugate) z)))
1661 ;; On the negative real axis or no information. Unsimplified.
1662 (list '($conjugate simp) (take '(%expintegral_ci) z))))))
1664 ;;; Differentiation of Exponential Integral Ci
1666 (defprop %expintegral_ci
1667 ((x)
1668 ((mtimes) ((%cos) x) ((mexpt) x -1)))
1669 grad)
1671 ;;; Integral of Exponential Ci
1673 (defprop %expintegral_ci
1674 ((x)
1675 ((mplus)
1676 ((mtimes) x ((%expintegral_ci) x))
1677 ((mtimes) -1 ((%sin) x))))
1678 integral)
1680 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1682 ;;; We support a simplim%function. The function is looked up in simplimit and
1683 ;;; handles specific values of the function.
1685 (defprop %expintegral_ci simplim%expintegral_ci simplim%function)
1687 (defun simplim%expintegral_ci (expr var val)
1688 ;; Look for the limit of the argument.
1689 (let ((z (limit (cadr expr) var val 'think)))
1690 (cond
1691 ;; Handle an argument 0 at this place
1692 ((or (zerop1 z)
1693 (eq z '$zeroa)
1694 (eq z '$zerob))
1695 '$minf)
1697 ;; All other cases are handled by the simplifier of the function.
1698 (take '(%expintegral_ci) z)))))
1700 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1702 ;;; Exponential Integral Ci is a simplifying function
1703 (def-simplifier expintegral_ci (arg)
1704 (cond
1705 ;; Check for special values
1706 ((zerop1 arg)
1707 (simp-domain-error
1708 (intl:gettext "expintegral_ci: expintegral_ci(~:M) is undefined.") arg))
1709 ((or (eq arg '$inf)
1710 (alike1 arg '((mtimes) -1 $minf)))
1712 ((or (eq arg '$minf)
1713 (alike1 arg '((mtimes) -1 $inf)))
1714 (mul '$%i '$%pi))
1716 ;; Check for numerical evaluation
1717 ((complex-float-numerical-eval-p arg)
1718 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1719 (complexify (expintegral-ci carg))))
1721 ((complex-bigfloat-numerical-eval-p arg)
1722 (let* (($ratprint nil)
1723 (carg (add ($bfloat ($realpart arg))
1724 (mul '$%i ($bfloat ($imagpart arg)))))
1725 (result (bfloat-expintegral-ci carg)))
1726 (add (mul '$%i ($imagpart result))
1727 ($realpart result))))
1729 ;; Check for argument simplifications and transformations
1730 ((taylorize (mop form) (second form)))
1732 ((and $expintrep
1733 (member $expintrep *expintflag*)
1734 (not (eq $expintrep '$expintegral_trig)))
1735 (case $expintrep
1736 (%gamma_incomplete
1737 (sub (take '(%log) arg)
1738 (mul (inv 2)
1739 (add (take '(%gamma_incomplete) 0 (mul -1 '$%i arg))
1740 (take '(%gamma_incomplete) 0 (mul '$%i arg))
1741 (take '(%log) (mul -1 '$%i arg))
1742 (take '(%log) (mul '$%i arg))))))
1743 (%expintegral_e1
1744 (add (mul (inv -2)
1745 (add (take '(%expintegral_e1) (mul -1 '$%i arg))
1746 (take '(%expintegral_e1) (mul '$%i arg)))
1747 (take '(%log) (mul -1 '$%i arg))
1748 (take '(%log) (mul '$%i arg)))
1749 (take '(%log) arg)))
1750 (%expintegral_ei
1751 (add (mul (inv 4)
1752 (add (mul 2
1753 (add (take '(%expintegral_ei) (mul -1 '$%i arg))
1754 (take '(%expintegral_ei) (mul '$%i arg))))
1755 (take '(%log) (div '$%i arg))
1756 (take '(%log) (mul -1 '$%i (inv arg)))
1757 (mul -1 (take '(%log) (mul -1 '$%i arg)))
1758 (mul -1 (take '(%log) (mul '$%i arg)))))
1759 (take '(%log) arg)))
1760 (%expintegral_li
1761 (add (mul (inv 2)
1762 (add (take '(%expintegral_li)
1763 (power '$%e (mul -1 '$%i arg)))
1764 (take '(%expintegral_li)
1765 (power '$%e (mul '$%i arg)))))
1766 (mul (div (mul '$%i '$%pi) 2)
1767 (take '(%signum) ($imagpart arg)))
1768 (sub 1 (take '(%signum) ($realpart arg)))))
1769 ($expintegral_hyp
1770 (add (take '(%expintegral_chi) (mul '$%i arg))
1771 (mul -1 (take '(%log) (mul '$%i arg)))
1772 (take '(%log) arg)))))
1774 ($hypergeometric_representation
1775 ;; See http://functions.wolfram.com/06.38.26.0001.01
1777 ;; expintegral_ci(z) = -z^2/4*hypergeometric([1,1],[2,2,3/2],-z^2/4)
1778 ;; + log(z) + %gamma
1780 (add
1781 (mul (div (mul arg arg) -4)
1782 (ftake '%hypergeometric
1783 (make-mlist 1 1)
1784 (make-mlist 2 2 3//2)
1785 (div (mul arg arg)
1786 -4)))
1787 (ftake '%log arg)
1788 '$%gamma))
1790 (give-up))))
1792 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1793 ;;; Numerical evaluation of the Exponential Integral Ci
1795 ;;; We use the representation:
1797 ;;; Ci(z) = -1/2 * (E1(-%i*z) + E1(%i*z) + log(-%i*z) + log(%i*z)) + log(z)
1799 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1801 (defun expintegral-ci (z)
1802 (let ((z (coerce z '(complex flonum))))
1803 (+ (* -0.5
1804 (+ (expintegral-e 1 (* (complex 0 -1) z))
1805 (expintegral-e 1 (* (complex 0 1) z))
1806 (log (* (complex 0 -1) z))
1807 (log (* (complex 0 1) z))))
1808 (log z))))
1810 (defun bfloat-expintegral-ci (z)
1811 (let ((z*%i (cmul '$%i z))
1812 (mz*%i (cmul (mul -1 '$%i) z)))
1813 (add
1814 (cmul
1815 -0.5
1816 (add
1817 (bfloat-expintegral-e 1 mz*%i)
1818 (bfloat-expintegral-e 1 z*%i)
1819 ($log mz*%i)
1820 ($log z*%i)))
1821 ($log z))))
1823 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1825 ;;; Part 8: The implementation of the Exponential Integral Chi
1827 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1829 ;;; Exponential Integral Chi distributes over bags
1831 (defprop %expintegral_chi (mlist $matrix mequal) distribute_over)
1833 ;;; Exponential Integral Chi has mirror symmetry,
1834 ;;; but not on the real negative axis.
1836 (defprop %expintegral_chi conjugate-expintegral-chi conjugate-function)
1838 (defun conjugate-expintegral-chi (args)
1839 (let ((z (first args)))
1840 (cond ((off-negative-real-axisp z)
1841 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1842 (take '(%expintegral_chi) (take '($conjugate) z)))
1844 ;; On the negative real axis or no information. Unsimplified.
1845 (list '($conjugate simp) (take '(%expintegral_chi) z))))))
1847 ;;; Differentiation of Exponential Integral Chi
1849 (defprop %expintegral_chi
1850 ((x)
1851 ((mtimes) ((%cosh) x) ((mexpt) x -1)))
1852 grad)
1854 ;;; Integral of Exponential Chi
1856 (defprop %expintegral_chi
1857 ((x)
1858 ((mplus)
1859 ((mtimes) x ((%expintegral_chi) x))
1860 ((mtimes) -1 ((%sinh) x))))
1861 integral)
1863 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1865 ;;; We support a simplim%function. The function is looked up in simplimit and
1866 ;;; handles specific values of the function.
1868 (defprop %expintegral_chi simplim%expintegral_chi simplim%function)
1870 (defun simplim%expintegral_chi (expr var val)
1871 ;; Look for the limit of the argument.
1872 (let ((z (limit (cadr expr) var val 'think)))
1873 (cond
1874 ;; Handle an argument 0 at this place
1875 ((or (zerop1 z)
1876 (eq z '$zeroa)
1877 (eq z '$zerob))
1878 '$minf)
1879 ((or (eq z '$inf)
1880 (eq z '$minf))
1881 '$inf)
1883 ;; All other cases are handled by the simplifier of the function.
1884 (take '(%expintegral_chi) z)))))
1886 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1888 ;;; Exponential Integral Chi is a simplifying function
1889 (def-simplifier expintegral_chi (arg)
1890 (cond
1891 ;; Check for special values
1892 ((zerop1 arg)
1893 ;; First check for zero argument. Throw Maxima error.
1894 (simp-domain-error
1895 (intl:gettext "expintegral_chi: expintegral_chi(~:M) is undefined.")
1896 arg))
1897 ((or (alike1 arg '((mtimes) $%i $inf))
1898 (alike1 arg '((mtimes) -1 $%i $minf)))
1899 (div (mul '$%pi '$%i) 2))
1900 ((or (alike1 arg '((mtimes) $%i $minf))
1901 (alike1 arg '((mtimes) -1 $%i $inf)))
1902 (div (mul -1 '$%pi '$%i) 2))
1904 ;; Check for numerical evaluation
1905 ((complex-float-numerical-eval-p arg)
1906 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1907 (complexify (expintegral-chi carg))))
1909 ((complex-bigfloat-numerical-eval-p arg)
1910 (let* (($ratprint nil)
1911 (carg (add ($bfloat ($realpart arg))
1912 (mul '$%i ($bfloat ($imagpart arg)))))
1913 (result (bfloat-expintegral-chi carg)))
1914 (add (mul '$%i ($imagpart result))
1915 ($realpart result))))
1917 ;; Check for argument simplifications and transformations
1918 ((taylorize (mop form) (second form)))
1920 ((and $expintrep
1921 (member $expintrep *expintflag*)
1922 (not (eq $expintrep '$expintegral_hyp)))
1923 (case $expintrep
1924 (%gamma_incomplete
1925 (mul (inv -2)
1926 (add (take '(%gamma_incomplete) 0 (mul -1 arg))
1927 (take '(%gamma_incomplete) 0 arg)
1928 (take '(%log) (mul -1 arg))
1929 (mul -1 (take '(%log) arg)))))
1930 (%expintegral_e1
1931 (mul (inv -2)
1932 (add (take '(%expintegral_e1) (mul -1 arg))
1933 (take '(%expintegral_e1) arg)
1934 (take '(%log) (mul -1 arg))
1935 (mul -1 (take '(%log) arg)))))
1936 (%expintegral_ei
1937 (mul (inv 4)
1938 (add (mul 2
1939 (add (take '(%expintegral_ei) (mul -1 arg))
1940 (take '(%expintegral_ei) arg)))
1941 (take '(%log) (inv arg))
1942 (take '(%log) (mul -1 (inv arg)))
1943 (mul -1 (take '(%log) (mul -1 arg)))
1944 (mul 3 (take '(%log) arg)))))
1945 (%expintegral_li
1946 (add (mul (inv 2)
1947 (add (take '(%expintegral_li) (power '$%e (mul -1 arg)))
1948 (take '(%expintegral_li) (power '$%e arg))))
1949 (mul (div (mul '$%i '$%pi) 2)
1950 (take '(%signum) ($imagpart arg)))
1951 (mul (inv 2)
1952 (add (take '(%log) (inv arg))
1953 (take '(%log) arg)))))
1954 ($expintegral_trig
1955 (add (take '(%expintegral_ci) (mul '$%i arg))
1956 (take '(%log) arg)
1957 (mul -1 (take '(%log) (mul '$%i arg)))))))
1959 ($hypergeometric_representation
1960 ;; See http://functions.wolfram.com/06.40.26.0001.01
1962 ;; expintegral_chi(z) = z^2/4*hypergeometric([1,1],[2,2,3/2],z^2/4)
1963 ;; + log(z) + %gamma
1965 (add
1966 (mul (div (mul arg arg) 4)
1967 (ftake '%hypergeometric
1968 (make-mlist 1 1)
1969 (make-mlist 2 2 3//2)
1970 (div (mul arg arg)
1971 4)))
1972 (ftake '%log arg)
1973 '$%gamma))
1975 (give-up))))
1977 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1978 ;;; Numerical evaluation of the Exponential Integral Ci
1980 ;;; We use the representation:
1982 ;;; Chi(z) = -1/2 * (E1(-z) + E1(z) + log(-z) - log(z))
1984 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1986 (defun expintegral-chi (z)
1988 -0.5
1990 (expintegral-e 1 z)
1991 (expintegral-e 1 (- z))
1992 (log (- z))
1993 (- (log z)))))
1995 (defun bfloat-expintegral-chi (z)
1996 (let ((mz (mul -1 z)))
1997 (mul
1998 -0.5
1999 (add
2000 (bfloat-expintegral-e 1 z)
2001 (bfloat-expintegral-e 1 mz)
2002 ($log mz)
2003 (mul -1 ($log z))))))
2005 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2006 ;; Moved from bessel.lisp 2008-12-11. Consider deleting it.
2008 ;; Exponential integral E1(x). The Cauchy principal value is used for
2009 ;; negative x.
2010 (defmfun $expint (x)
2011 (cond ((numberp x)
2012 (values (slatec:de1 (float x))))
2014 (list '($expint simp) x))))