1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; Exponential Integrals
5 ;;; This file contains the following Maxima User functions:
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)
11 ;;; $expintegral_li (z) - Logarithmic Integral Li(z)
13 ;;; $expintegral_si (z) - Exponential Integral Si(z)
14 ;;; $expintegral_ci (z) - Exponential Integral Ci(z)
16 ;;; $expintegral_shi (z) - Exponential Integral Shi(z)
17 ;;; $expintegral_chi (z) - Exponential Integral Chi(z)
19 ;;; $expint (x) - Exponential Integral E1(x) (depreciated)
21 ;;; Global variables for the Maxima User:
23 ;;; $expintrep - Change the representation of the Exponential Integral to
24 ;;; gamma_incomplete, expintegral_e1, expintegral_ei,
25 ;;; expintegral_li, expintegral_trig, expintegral_hyp
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
31 ;;; The following features are implemented:
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.
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.
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
45 ;;; 3. Simplifications for special values: Ev(0), E[0](z), Li(0), Li(1),...
47 ;;; 4. Derivatives of the Exponential Integrals
49 ;;; 5. Change the representation of every Exponential Integral through other
50 ;;; Exponential Integrals or the Incomplete Gamma function.
52 ;;; 6. Mirror symmetry for all functions and reflection symmetry for
53 ;;; the Exponential Inegral Si and Shi are implemented.
55 ;;; 7. Handling of taylor expansions as argument.
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.
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.
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
72 ;;; Copyright (C) 2008 Dieter Kaiser
73 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
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
)
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
))
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
155 ;; The derivative wrt the parameter n is expressed in terms of the
156 ;; Regularized Hypergeometric function 2F2 (see functions.wolfram.com)
159 (($hypergeometric_regularized
)
161 ((mplus) 1 ((mtimes) -
1 n
))
162 ((mplus) 1 ((mtimes) -
1 n
)))
164 ((mplus) 2 ((mtimes) -
1 n
))
165 ((mplus) 2 ((mtimes) -
1 n
)))
168 ((%gamma
) ((mplus) 1 ((mtimes) -
1 n
))) 2))
170 ((%gamma
) ((mplus) 1 ((mtimes) -
1 n
)))
171 ((mexpt) z
((mplus) -
1 n
))
176 ((mplus) 1 ((mtimes) -
1 n
))))
179 ;; The derivative wrt the argument of the function
180 ((mtimes) -
1 ((%expintegral_e
) ((mplus) -
1 n
) z
)))
183 ;;; Integral of Exponential Integral E
185 (defprop %expintegral_e
188 ((mtimes) -
1 ((%expintegral_e
) ((mplus) 1 n
) z
)))
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
)
206 ;; Special case order a=1
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
215 ;; this can be further improved to give a directed infinity
218 ;; no direction, return 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
)
232 ;; Check for special values
234 (alike1 arg
'((mtimes) -
1 $minf
)))
235 ;; arg is inf or -minf, return zero
239 (let ((sgn ($sign
(add ($realpart order
) -
1))))
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
))
247 "expintegral_e: expintegral_e(~:M,~:M) is undefined.")
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.
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.
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
))
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
)))
272 ;; We expand in a series, z<>0
274 (factorial (- order
))
275 (power arg
(+ order -
1))
276 (power '$%e
(mul -
1 arg
))
277 (let ((index (gensumindex)))
279 (div (power arg index
)
280 (take '(mfactorial) index
))
281 index
0 (- order
) t
))))
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
))))
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.
304 (power (mul -
1 arg
) (- order
1))
305 (inv (factorial (- order
1)))
306 (add (take '(%expintegral_ei
) (mul -
1 arg
))
308 (sub (take '(%log
) (mul -
1 (inv arg
)))
309 (take '(%log
) (mul -
1 arg
))))
311 (mul (power '$%e
(mul -
1 arg
))
312 (let ((index (gensumindex)))
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
)))
326 ((complex-float-numerical-eval-p order arg
)
329 ((and (setq z
(integer-representation-p order
))
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
)
348 ((and (setq z
(integer-representation-p order
))
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
))))))))
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)))))))
380 (mul (power '$%pi
'((rat simp
) 1 2))
381 (power arg
'((rat simp
) -
1 2))
386 (power '$%pi
'((rat simp
) 1 2))
387 (inv (mul 2 (power arg
'((rat simp
) 3 2))))
389 (div (power '$%e
(mul -
1 arg
)) arg
)))
391 (let ((n (- ratorder
1/2)))
393 (power arg
(sub n
'((rat simp
) 1 2)))
395 (mul func
(take '(%gamma
) (sub '((rat simp
) 1 2) n
)))
397 (power '$%e
(mul -
1 arg
))
398 (let ((index (gensumindex)))
401 (power arg
(add index
'((rat simp
) 1 2)))
403 (sub '((rat simp
) 1 2) n
)
405 index
0 (mul -
1 (add n
1)) t
)))
407 (power '$%e
(mul -
1 arg
))
408 (let ((index (gensumindex)))
411 (power arg
(add index
'((rat simp
) 1 2)))
413 (sub '((rat simp
) 1 2) n
)
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
))
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:
467 ;;; En(z) = e^(-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
477 ;;; (-z)^(n-1) \ (-z)^m
478 ;;; En(z) = --------- * (-log(z)+psi(n)) * > ---------- ; n an integer
479 ;;; (n-1)! / (m-n+1)*m!
483 ;;; For an parameter n not an integer we expand in the following series
484 ;;; (functions.wolfram.com ):
488 ;;; Ev(z) = gamma(1-v) * z^(v-1) * > ------------- ; n not an integer
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
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
))
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.~%"))
541 (c (/ 1.0 (* *expint-eps
* *expint-eps
*)))
547 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
548 ((> i
*expint-maxit
*)
550 (intl:gettext
"expintegral_e: continued fractions failed.")))
553 (setq d
(/ 1.0 (+ (* a d
) b
)))
554 (setq c
(+ b
(/ a c
)))
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.~%"))
567 (euler (mget '$%gamma
'$numer
))
568 (r (if (= n1
0) (- (- euler
) (log z
)) (/ 1.0 n1
)))
572 ((> i
*expint-maxit
*)
573 (merror (intl:gettext
"expintegral_e: series failed.")))
574 (setq f
(* -
1 f
(/ z i
)))
577 (let ((psi (- euler
)))
579 (setq psi
(+ psi
(/ 1.0 (+ ii
1)))))
580 (setq e
(* f
(- psi
(log z
))))))
582 (setq e
(/ (- f
) (- i n1
)))))
584 (when (< (abs e
) (* (abs r
) *expint-eps
*))
585 (when *debug-expintegral
*
586 (setq *debug-expint-maxit
* (max *debug-expint-maxit
* i
)))
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
))
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.~%"))
611 (c (/ 1.0 (* *expint-eps
* *expint-eps
*)))
617 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
618 ((> i
*expint-maxit
*)
620 (intl:gettext
"expintegral_e: continued fractions failed.")))
623 (setq d
(/ 1.0 (+ (* a d
) b
)))
624 (setq c
(+ b
(/ a c
)))
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)
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.~%"))
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
))))
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
)))
662 (when (< (abs e
) (* (abs r
) *expint-eps
*))
663 (when *debug-expintegral
*
664 (setq *debug-expint-fracmaxit
* (max *debug-expint-fracmaxit
* i
)))
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
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
))
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.~%"))
710 (c (div bigfloatone
(mul *expint-eps
* *expint-eps
*)))
711 (d (cdiv bigfloatone b
))
716 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
717 ((> i
*expint-maxit
*)
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
)))
727 (when (eq ($sign
(sub (cabs (sub e bigfloatone
)) *expint-eps
*))
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.~%"))
738 (meuler (mul -
1 bigfloat%gamma
))
739 (r (if (= n1
0) (sub meuler
($log z
)) (div bigfloatone n1
)))
743 ((> i
*expint-maxit
*)
744 (merror (intl:gettext
"expintegral_e: series failed.")))
745 (setq f
(mul -
1 (cmul f
(cdiv z i
))))
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
)))))
755 (when (eq ($sign
(sub (cabs e
) (cmul (cabs r
) *expint-eps
*)))
757 (when *debug-expintegral
*
758 (setq *debug-expint-bfloatmaxit
*
759 (max *debug-expint-bfloatmaxit
* i
)))
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
))
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.~%"))
789 (c (div bigfloatone
(mul *expint-eps
* *expint-eps
*)))
790 (d (cdiv bigfloatone b
))
795 (a (mul -
1 n
) (cmul (- i
) (add n1 i
))))
796 ((> i
*expint-maxit
*)
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
)))
806 (when (eq ($sign
(sub (cabs (sub e bigfloatone
)) *expint-eps
*))
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
)
816 (= (nth-value 1 (truncate ($realpart n
))) 0))
819 (equal (sub (mul 2 ($fix n
)) (mul 2 n
))
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
)))
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
)))
844 (when (eq ($sign
(sub (cabs e
) (cmul (cabs r
) *expint-eps
*)))
846 (when *debug-expintegral
*
847 (setq *debug-expint-fracbfloatmaxit
*
848 (max *debug-expint-fracbfloatmaxit
* i
)))
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
881 ((mexpt) $%e
((mtimes) -
1 x
))))
884 ;;; Integral of Exponential Integral E1
886 (defprop %expintegral_e1
888 ((mtimes) -
1 ((%expintegral_e
) 2 z
)))
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
)))
902 ;; Handle an argument 0 at this place
906 ;; limit is inf from both sides
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)
917 ;; Check for special values
919 (alike1 arg
'((mtimes) -
1 $minf
)))
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
)))
944 (member $expintrep
*expintflag
* :test
#'eq
)
945 (not (eq $expintrep
'%expintegral_e1
)))
948 (take '(%gamma_incomplete
) 0 arg
))
950 (add (mul -
1 (take '(%expintegral_ei
) (mul -
1 arg
)))
952 (sub (take '(%log
) (mul -
1 arg
))
953 (take '(%log
) (mul -
1 (inv arg
)))))
954 (mul -
1 (take '(%log
) arg
))))
956 (add (mul -
1 (take '(%expintegral_li
) (power '$%e
(mul -
1 arg
))))
957 (mul -
1 (take '(%log
) arg
))
959 (sub (take '(%log
) (mul -
1 arg
))
960 (take '(%log
) (mul -
1 (inv arg
)))))))
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
))))
967 (sub (take '(%expintegral_shi
) arg
)
968 (take '(%expintegral_chi
) arg
)))
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
993 ((mtimes) ((mexpt) x -
1) ((mexpt) $%e x
)))
996 ;;; Integral of Exponential Ei
998 (defprop %expintegral_ei
1001 ((mtimes) -
1 ((mexpt) $%e x
))
1002 ((mtimes) x
((%expintegral_ei
) x
))))
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
)))
1016 ;; Handle an argument 0 at this place
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)
1030 ;; Check special values
1033 (intl:gettext
"expintegral_ei: expintegral_ei(~:M) is undefined.")
1036 (alike1 arg
'((mtimes) -
1 $minf
)))
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
)))
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
)))
1065 (member $expintrep
*expintflag
*)
1066 (not (eq $expintrep
'%expintegral_ei
)))
1069 (add (mul -
1 (take '(%gamma_incomplete
) 0 (mul -
1 arg
)))
1071 (sub (take '(%log
) arg
)
1072 (take '(%log
) (inv arg
))))
1073 (mul -
1 (take '(%log
) (mul -
1 arg
)))))
1075 (add (mul -
1 (take '(%expintegral_e1
) (mul -
1 arg
)))
1077 (sub (take '(%log
) arg
)
1078 (take '(%log
) (inv arg
))))
1079 (mul -
1 (take '(%log
) (mul -
1 arg
)))))
1081 (take '(%expintegral_li
) (power '$%e arg
)))
1083 (add (take '(%expintegral_ci
) (mul '$%i arg
))
1084 (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i arg
)))
1086 (sub (take '(%log
) (inv arg
))
1087 (take '(%log
) arg
)))
1088 (mul -
1 (take '(%log
) (mul '$%i arg
)))))
1090 (add (take '(%expintegral_chi
) arg
)
1091 (take '(%expintegral_shi
) arg
)
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).
1107 (ftake '%hypergeometric
1112 (sub (ftake '%log arg
)
1113 (ftake '%log
(div 1 arg
))))
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.)
1136 ;; Positive imaginary part. Add phase %i*%pi.
1137 (complex 0 (float pi
)))
1139 ;; Negative imaginary part. Add phase -%i*%pi.
1140 (complex 0 (- (float pi
))))
1142 ;; Positive real value. Add phase -%i*pi.
1143 (complex 0 (- (float pi
))))
1144 ;; Negative real value. No phase factor.
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
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
1192 ((mtimes) ((mexpt) ((%log
) x
) -
1)))
1195 ;;; Integral of Exponential Li
1197 (defprop %expintegral_li
1200 ((mtimes) x
((%expintegral_li
) x
))
1201 ((mtimes) -
1 ((%expintegral_ei
) ((mtimes) 2 ((%log
) x
))))))
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
)))
1215 ;; Handle an argument 1 at this place
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)
1229 (intl:gettext
"expintegral_li: expintegral_li(~:M) is undefined.") arg
))
1231 (alike1 arg
'((mtimes) -
1 $minf
)))
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
)))
1251 (member $expintrep
*expintflag
*)
1252 (not (eq $expintrep
'%expintegral_li
)))
1253 (let ((logarg (take '(%log
) arg
)))
1256 (add (mul -
1 (take '(%gamma_incomplete
) 0 (mul -
1 logarg
)))
1258 (sub (take '(%log
) logarg
)
1259 (take '(%log
) (inv logarg
))))
1260 (mul -
1 (take '(%log
) (mul -
1 logarg
)))))
1262 (add (mul -
1 (take '(%expintegral_e1
) (mul -
1 logarg
)))
1264 (sub (take '(%log
) logarg
)
1265 (take '(%log
) (inv logarg
))))
1266 (mul -
1 (take '(%log
) (mul -
1 logarg
)))))
1268 (take '(%expintegral_ei
) logarg
))
1270 (add (take '(%expintegral_ci
) (mul '$%i logarg
))
1271 (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i logarg
)))
1273 (sub (take '(%log
) (inv logarg
))
1274 (take '(%log
) logarg
)))
1275 (mul -
1 (take '(%log
) (mul '$%i logarg
)))))
1277 (add (take '(%expintegral_chi
) logarg
)
1278 (take '(%expintegral_shi
) logarg
)
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
1298 (sub (ftake '%log
(ftake '%log arg
))
1299 (ftake '%log
(div 1 (ftake '%log arg
)))))
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
1340 ((mtimes) ((%sin
) x
) ((mexpt) x -
1)))
1343 ;;; Integral of Exponential Si
1345 (defprop %expintegral_si
1349 ((mtimes) x
((%expintegral_si
) x
))))
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)
1369 ;; Check for special values
1372 (alike1 arg
'((mtimes) -
1 $minf
)))
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
))
1396 (member $expintrep
*expintflag
*)
1397 (not (eq $expintrep
'$expintegral_trig
)))
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
))))))
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
))))))
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
)))))
1421 (mul (inv (mul 2 '$%i
))
1422 (add (take '(%expintegral_li
) (power '$%e
(mul '$%i arg
)))
1424 (take '(%expintegral_li
)
1425 (power '$%e
(mul -
1 '$%e arg
))))
1427 (take '(%signum
) ($realpart arg
))))))
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)
1437 (ftake '%hypergeometric
1439 (make-mlist 3//2 3//2)
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
))))
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
)))
1471 (bfloat-expintegral-e 1 mz
*%i
)
1472 (mul -
1 (bfloat-expintegral-e 1 z
*%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
1498 ((mtimes) ((%sinh
) x
) ((mexpt) x -
1)))
1501 ;;; Integral of Exponential Shi
1503 (defprop %expintegral_shi
1506 ((mtimes) -
1 ((%cosh
) x
))
1507 ((mtimes) x
((%expintegral_shi
) x
))))
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
)))
1521 ;; Handle infinities at this place
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)
1535 ;; Check for special values
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
))
1565 (member $expintrep
*expintflag
*)
1566 (not (eq $expintrep
'$expintegral_hyp
)))
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
))))
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
))))
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
)))))
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
)))))
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)
1604 (ftake '%hypergeometric
1606 (make-mlist 3//2 3//2)
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)
1626 (- (expintegral-e 1 (- z
)))
1630 (defun bfloat-expintegral-shi (z)
1631 (let ((mz (mul -
1 z
)))
1635 (bfloat-expintegral-e 1 z
)
1636 (mul -
1 (bfloat-expintegral-e 1 mz
))
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
1668 ((mtimes) ((%cos
) x
) ((mexpt) x -
1)))
1671 ;;; Integral of Exponential Ci
1673 (defprop %expintegral_ci
1676 ((mtimes) x
((%expintegral_ci
) x
))
1677 ((mtimes) -
1 ((%sin
) x
))))
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
)))
1691 ;; Handle an argument 0 at this place
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)
1705 ;; Check for special values
1708 (intl:gettext
"expintegral_ci: expintegral_ci(~:M) is undefined.") arg
))
1710 (alike1 arg
'((mtimes) -
1 $minf
)))
1712 ((or (eq arg
'$minf
)
1713 (alike1 arg
'((mtimes) -
1 $inf
)))
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
)))
1733 (member $expintrep
*expintflag
*)
1734 (not (eq $expintrep
'$expintegral_trig
)))
1737 (sub (take '(%log
) arg
)
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
))))))
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
)))
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
)))
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
)))))
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
1781 (mul (div (mul arg arg
) -
4)
1782 (ftake '%hypergeometric
1784 (make-mlist 2 2 3//2)
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
))))
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
))))
1810 (defun bfloat-expintegral-ci (z)
1811 (let ((z*%i
(cmul '$%i z
))
1812 (mz*%i
(cmul (mul -
1 '$%i
) z
)))
1817 (bfloat-expintegral-e 1 mz
*%i
)
1818 (bfloat-expintegral-e 1 z
*%i
)
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
1851 ((mtimes) ((%cosh
) x
) ((mexpt) x -
1)))
1854 ;;; Integral of Exponential Chi
1856 (defprop %expintegral_chi
1859 ((mtimes) x
((%expintegral_chi
) x
))
1860 ((mtimes) -
1 ((%sinh
) x
))))
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
)))
1874 ;; Handle an argument 0 at this place
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)
1891 ;; Check for special values
1893 ;; First check for zero argument. Throw Maxima error.
1895 (intl:gettext
"expintegral_chi: expintegral_chi(~:M) is undefined.")
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
)))
1921 (member $expintrep
*expintflag
*)
1922 (not (eq $expintrep
'$expintegral_hyp
)))
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
)))))
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
)))))
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
)))))
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
)))
1952 (add (take '(%log
) (inv arg
))
1953 (take '(%log
) arg
)))))
1955 (add (take '(%expintegral_ci
) (mul '$%i 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
1966 (mul (div (mul arg arg
) 4)
1967 (ftake '%hypergeometric
1969 (make-mlist 2 2 3//2)
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)
1991 (expintegral-e 1 (- z
))
1995 (defun bfloat-expintegral-chi (z)
1996 (let ((mz (mul -
1 z
)))
2000 (bfloat-expintegral-e 1 z
)
2001 (bfloat-expintegral-e 1 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
2010 (defmfun $expint
(x)
2012 (values (slatec:de1
(float x
))))
2014 (list '($expint simp
) x
))))