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
)
328 ((and (setq z
(integer-representation-p order
))
330 ;; We have a pure real positive order and the realpart is a float
331 ;; representation of an integer value.
332 ;; We call the routine for an integer order.
333 (let ((carg (complex ($float
($realpart arg
))
334 ($float
($imagpart arg
)))))
335 (complexify (expintegral-e z carg
))))
337 ;; The general case, order and arg are complex or real.
338 (let ((corder (complex ($float
($realpart order
))
339 ($float
($imagpart order
))))
340 (carg (complex ($float
($realpart arg
))
341 ($float
($imagpart arg
)))))
342 (complexify (frac-expintegral-e corder carg
))))))
344 ((complex-bigfloat-numerical-eval-p order arg
)
346 ((and (setq z
(integer-representation-p order
))
348 ;; We have a real positive order and the realpart is a Float or
349 ;; Bigfloat representation of an integer value.
350 ;; We call the routine for an integer order.
351 (let* (($ratprint nil
)
352 (carg (add ($bfloat
($realpart arg
))
353 (mul '$%i
($bfloat
($imagpart arg
)))))
354 (result (bfloat-expintegral-e z carg
)))
355 (add ($realpart result
)
356 (mul '$%i
($imagpart result
)))))
358 ;; the general case, order and arg are bigfloat or complex bigfloat
359 (let* (($ratprint nil
)
360 (corder (add ($bfloat
($realpart order
))
361 (mul '$%i
($bfloat
($imagpart order
)))))
362 (carg (add ($bfloat
($realpart arg
))
363 (mul '$%i
($bfloat
($imagpart arg
)))))
364 (result (frac-bfloat-expintegral-e corder carg
)))
365 (add ($realpart result
)
366 (mul '$%i
($imagpart result
)))))))
369 (setq ratorder
(max-numeric-ratio-p order
2)))
370 ;; We have a half integral order and $expintexpand is not NIL.
371 ;; We expand in a series in terms of the Erfc or Erf function.
372 (let ((func (cond ((eq $expintexpand
'%erf
)
373 (sub 1 ($erf
(power arg
'((rat simp
) 1 2)))))
375 ($erfc
(power arg
'((rat simp
) 1 2)))))))
378 (mul (power '$%pi
'((rat simp
) 1 2))
379 (power arg
'((rat simp
) -
1 2))
384 (power '$%pi
'((rat simp
) 1 2))
385 (inv (mul 2 (power arg
'((rat simp
) 3 2))))
387 (div (power '$%e
(mul -
1 arg
)) arg
)))
389 (let ((n (- ratorder
1/2)))
391 (power arg
(sub n
'((rat simp
) 1 2)))
393 (mul func
(take '(%gamma
) (sub '((rat simp
) 1 2) n
)))
395 (power '$%e
(mul -
1 arg
))
396 (let ((index (gensumindex)))
399 (power arg
(add index
'((rat simp
) 1 2)))
401 (sub '((rat simp
) 1 2) n
)
403 index
0 (mul -
1 (add n
1)) t
)))
405 (power '$%e
(mul -
1 arg
))
406 (let ((index (gensumindex)))
409 (power arg
(add index
'((rat simp
) 1 2)))
411 (sub '((rat simp
) 1 2) n
)
413 index
(- n
) -
1 t
))))))))))
415 ((eq $expintrep
'%gamma_incomplete
)
416 ;; We transform to the Incomplete Gamma function.
417 (mul (power arg
(sub order
1))
418 (take '(%gamma_incomplete
) (sub 1 order
) arg
)))
423 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
424 ;;; Numerical evaluation of the Exponential Integral En(z)
426 ;;; The following numerical routines are implemented:
428 ;;; expintegral-e - n positive integer, z real or complex
429 ;;; frac-expintegral-e - n,z real or complex; n not a positive integer
430 ;;; bfloat-expintegral-e - n positive integer,
431 ;;; z Bigfloat or Complex Bigfloat
432 ;;; frac-bfloat-expintegral-e - n Bigfloat, z Bigfloat or Complex Bigfloat
434 ;;; The algorithm are implemented for full support of Flonum and Bigfloat real
435 ;;; or Complex parameter and argument of the Exponential Integral.
436 ;;; Because we have no support for Complex Bigfloat arguments of the Gamma
437 ;;; function the evaluation for a Complex Bigfloat parameter don't give
438 ;;; the desiered accuracy.
440 ;;; The flonum versions return a CL complex number. The Bigfloat versions
441 ;;; a Maxima Complex Bigfloat number. It is assumed that the calling routine
442 ;;; check the values. We don't handle any special case. This has to be done by
443 ;;; the calling routine.
445 ;;; The evaluation uses an expansion in continued fractions for arguments with
446 ;;; realpart(z) > 0 and abs(z)> 1.0 (A&S 5.1.22). This expansion works for
447 ;;; every Real or Complex numbers including Bigfloat numbers for the parameter n
448 ;;; and the argument z:
451 ;;; En(z) = e^(-z) * ( --- --- --- --- --- ... )
454 ;;; The continued fraction is evaluated by the modified Lentz's method
455 ;;; for the more rapidly converging even form.
457 ;;; For the parameter n an positive integer we do an expansion in a power series
461 ;;; (-z)^(n-1) \ (-z)^m
462 ;;; En(z) = --------- * (-log(z)+psi(n)) * > ---------- ; n an integer
463 ;;; (n-1)! / (m-n+1)*m!
467 ;;; For an parameter n not an integer we expand in the following series
468 ;;; (functions.wolfram.com ):
472 ;;; Ev(z) = gamma(1-v) * z^(v-1) * > ------------- ; n not an integer
477 ;;; The evaluation stops if an accuracy better than *expint-eps* is achieved.
478 ;;; If the expansion don't converge within *expint-maxit* steps a Maxima
481 ;;; The algorithm is based on technics desribed in Numerical Recipes, 2nd Ed.
482 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
484 ;;; Constants to terminate the numerical evaluation
486 ;;; The accuracy *expint-eps* is fixed to 1.0e-15 for double float calculations.
487 ;;; The variable is declared global, so we can later give the Maxima User access
488 ;;; to the variable. The routine for Bigfloat numerical evaluation change this
489 ;;; value to the desired precision of the global $fpprec.
490 ;;; The maximum number of iterations is arbitrary set to 1000. For Bigfloat
491 ;;; evaluation this number is for very Big numbers too small.
493 ;;; The maximum iterations counted for the test file rtest-expintegral.mac are
494 ;;; 101 for Complex Flonum and 1672 for Complex Bigfloat evaluation.
496 (defvar *expint-eps
* 1.0e-15)
497 (defvar *expint-maxit
* 1000)
499 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
501 (defun expintegral-e (n z
)
502 (declare (type integer n
))
503 (let ((*expint-eps
* *expint-eps
*)
504 (*expint-maxit
* *expint-maxit
*)
505 ;; Add (complex) 0 to get rid of any signed zeroes, and make z
506 ;; be a complex number.
507 (z (+ (coerce 0 '(complex flonum
)) z
)))
508 (declare (type (complex flonum
) z
))
510 (when *debug-expintegral
*
511 (format t
"~&EXPINTEGRAL-E called with:~%")
512 (format t
"~& : n = ~A~%" n
)
513 (format t
"~& : z = ~A~%" z
))
516 ((or (and (> (abs z
) 2.0) (< (abs (phase z
)) (* pi
0.9)))
517 ;; (abs z)>2.0 is necessary since there is a point
518 ;; -1.700598-0.612828*%i which 1<(abs z)<2, phase z < 0.9pi and
519 ;; still c-f expansion does not converge.
520 (and (>= (realpart z
) 0) (> (abs z
) 1.0)))
521 ;; We expand in continued fractions.
522 (when *debug-expintegral
*
523 (format t
"~&We expand in continued fractions.~%"))
525 (c (/ 1.0 (* *expint-eps
* *expint-eps
*)))
531 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
532 ((> i
*expint-maxit
*)
534 (intl:gettext
"expintegral_e: continued fractions failed.")))
537 (setq d
(/ 1.0 (+ (* a d
) b
)))
538 (setq c
(+ b
(/ a c
)))
542 (when (< (abs (- e
1.0)) *expint-eps
*)
543 (when *debug-expintegral
*
544 (setq *debug-expint-maxit
* (max *debug-expint-maxit
* i
)))
545 (return (* h
(exp (- z
))))))))
547 ;; We expand in a power series.
548 (when *debug-expintegral
*
549 (format t
"~&We expand in a power series.~%"))
551 (euler (mget '$%gamma
'$numer
))
552 (r (if (= n1
0) (- (- euler
) (log z
)) (/ 1.0 n1
)))
556 ((> i
*expint-maxit
*)
557 (merror (intl:gettext
"expintegral_e: series failed.")))
558 (setq f
(* -
1 f
(/ z i
)))
561 (let ((psi (- euler
)))
563 (setq psi
(+ psi
(/ 1.0 (+ ii
1)))))
564 (setq e
(* f
(- psi
(log z
))))))
566 (setq e
(/ (- f
) (- i n1
)))))
568 (when (< (abs e
) (* (abs r
) *expint-eps
*))
569 (when *debug-expintegral
*
570 (setq *debug-expint-maxit
* (max *debug-expint-maxit
* i
)))
573 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
574 ;;; Numerical evaluation for a real or complex parameter.
575 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
577 (defun frac-expintegral-e (n z
)
578 (declare (type (complex flonum
) n
)
579 (type (complex flonum
) z
))
581 (let ((*expint-eps
* *expint-eps
*)
582 (*expint-maxit
* *expint-maxit
*))
584 (when *debug-expintegral
*
585 (format t
"~&FRAC-EXPINTEGRAL-E called with:~%")
586 (format t
"~& : n = ~A~%" n
)
587 (format t
"~& : z = ~A~%" z
))
590 ((and (> (realpart z
) 0) (> (abs z
) 1.0))
591 ;; We expand in continued fractions.
592 (when *debug-expintegral
*
593 (format t
"~&We expand in continued fractions.~%"))
595 (c (/ 1.0 (* *expint-eps
* *expint-eps
*)))
601 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
602 ((> i
*expint-maxit
*)
604 (intl:gettext
"expintegral_e: continued fractions failed.")))
607 (setq d
(/ 1.0 (+ (* a d
) b
)))
608 (setq c
(+ b
(/ a c
)))
612 (when (< (abs (- e
1.0)) *expint-eps
*)
613 (when *debug-expintegral
*
614 (setq *debug-expint-fracmaxit
* (max *debug-expint-fracmaxit
* i
)))
615 (return (* h
(exp (- z
))))))))
617 ((and (= (imagpart n
) 0)
619 (= (nth-value 1 (truncate (realpart n
))) 0))
620 ;; We have a positive integer n or an float representation of an
621 ;; integer. We call expintegral-e which does this calculation.
622 (when *debug-expintegral
*
623 (format t
"~&We call expintegral-e.~%"))
624 (expintegral-e (truncate (realpart n
)) z
))
627 ;; At this point the parameter n is a real (not an float representation
628 ;; of an integer) or complex. We expand in a power series.
629 (when *debug-expintegral
*
630 (format t
"~&We expand in a power series.~%"))
632 ;; It would be possible to call the numerical implementation
633 ;; gamm-lanczos directly. But then the code would depend on the
634 ;; details of the implementation.
635 (gm (let ((tmp (take '(%gamma
) (complexify (- 1 n
)))))
636 (complex ($realpart tmp
) ($imagpart tmp
))))
637 (r (- (* (expt z n1
) gm
) (/ 1.0 (- 1 n
))))
641 ((> i
*expint-maxit
*)
642 (merror (intl:gettext
"expintegral_e: series failed.")))
643 (setq f
(* -
1 f
(/ z
(float i
))))
644 (setq e
(/ (- f
) (- (float i
) n1
)))
646 (when (< (abs e
) (* (abs r
) *expint-eps
*))
647 (when *debug-expintegral
*
648 (setq *debug-expint-fracmaxit
* (max *debug-expint-fracmaxit
* i
)))
651 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
652 ;;; Helper functions for Bigfloat numerical evaluation.
653 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
655 (defun cmul (x y
) ($rectform
(mul x y
)))
657 (defun cdiv (x y
) ($rectform
(div x y
)))
659 (defun cpower (x y
) ($rectform
(power x y
)))
661 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
662 ;;; We have not changed the above algorithm, but generalized it to handle
663 ;;; complex and real Bigfloat numbers. By carefully examination of the
664 ;;; algorithm some of the additional calls to $rectform can be eliminated.
665 ;;; But the algorithm works and so we leave the extra calls for later work
667 ;;; The accuracy of the result is determined by *expint-eps*. The value is
668 ;;; chosen to correspond to the value of $fpprec. We don't give any extra
669 ;;; digits to fpprec, so we loose 1 to 2 digits of precision.
670 ;;; One problem is to chose a sufficient big *expint-maxit*.
671 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
673 (defun bfloat-expintegral-e (n z
)
674 (let ((*expint-eps
* (power ($bfloat
10.0) (- $fpprec
)))
675 (*expint-maxit
* 5000) ; arbitrarily chosen, we need a better choice
676 (bigfloattwo (add bigfloatone bigfloatone
))
677 (bigfloat%e
($bfloat
'$%e
))
678 (bigfloat%gamma
($bfloat
'$%gamma
))
679 (flz (complex ($float
($realpart z
)) ($float
($imagpart z
)))))
681 (when *debug-expintegral
*
682 (format t
"~&BFLOAT-EXPINTEGRAL-E called with:~%")
683 (format t
"~& : n = ~A~%" n
)
684 (format t
"~& : z = ~A~%" flz
))
687 ((or (and (> (abs flz
) 2) (< (abs (phase flz
)) (* pi
0.9)))
688 ;; The same condition as you see in expintegral-e()
689 (and (>= (realpart flz
) 0) (> (abs flz
) 1.0)))
690 ;; We expand in continued fractions.
691 (when *debug-expintegral
*
692 (format t
"~&We expand in continued fractions.~%"))
694 (c (div bigfloatone
(mul *expint-eps
* *expint-eps
*)))
695 (d (cdiv bigfloatone b
))
700 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
701 ((> i
*expint-maxit
*)
703 (intl:gettext
"expintegral_e: continued fractions failed.")))
705 (setq b
(add b bigfloattwo
))
706 (setq d
(cdiv bigfloatone
(add (mul a d
) b
)))
707 (setq c
(add b
(cdiv a c
)))
711 (when (eq ($sign
(sub (cabs (sub e bigfloatone
)) *expint-eps
*))
713 (when *debug-expintegral
*
714 (setq *debug-expint-bfloatmaxit
*
715 (max *debug-expint-bfloatmaxit
* i
)))
716 (return (cmul h
(cpower bigfloat%e
(mul -
1 z
))))))))
718 ;; We expand in a power series.
719 (when *debug-expintegral
*
720 (format t
"~&We expand in a power series.~%"))
722 (meuler (mul -
1 bigfloat%gamma
))
723 (r (if (= n1
0) (sub meuler
($log z
)) (div bigfloatone n1
)))
727 ((> i
*expint-maxit
*)
728 (merror (intl:gettext
"expintegral_e: series failed.")))
729 (setq f
(mul -
1 (cmul f
(cdiv z i
))))
734 (setq psi
(add psi
(cdiv bigfloatone
(+ ii
1)))))
735 (setq e
(cmul f
(sub psi
($log z
))))))
737 (setq e
(cdiv (mul -
1 f
) (- i n1
)))))
739 (when (eq ($sign
(sub (cabs e
) (cmul (cabs r
) *expint-eps
*)))
741 (when *debug-expintegral
*
742 (setq *debug-expint-bfloatmaxit
*
743 (max *debug-expint-bfloatmaxit
* i
)))
746 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
747 ;;; Numerical Bigfloat evaluation for a real (Bigfloat) parameter.
748 ;;; The algorithm would work for a Complex Bigfloat parameter too. But we
749 ;;; need the values of Gamma for Complex Bigfloats. This is at this time (2008)
750 ;;; not implemented in Maxima.
751 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
753 (defun frac-bfloat-expintegral-e (n z
)
754 (let ((*expint-eps
* (power ($bfloat
10.0) (- $fpprec
)))
755 (*expint-maxit
* 5000) ; arbitrarily chosen, we need a better choice
756 (bigfloattwo (add bigfloatone bigfloatone
))
757 (bigfloat%e
($bfloat
'$%e
))
758 (bigfloat%gamma
($bfloat
'$%gamma
)))
760 (when *debug-expintegral
*
761 (format t
"~&FRAC-BFLOAT-EXPINTEGRAL-E called with:~%")
762 (format t
"~& : n = ~A~%" n
)
763 (format t
"~& : z = ~A~%" z
))
766 ((and (or (eq ($sign
($realpart z
)) '$pos
)
767 (eq ($sign
($realpart z
)) '$zero
))
768 (eq ($sign
(sub (cabs z
) bigfloatone
)) '$pos
))
769 ;; We expand in continued fractions.
770 (when *debug-expintegral
*
771 (format t
"We expand in continued fractions.~%"))
773 (c (div bigfloatone
(mul *expint-eps
* *expint-eps
*)))
774 (d (cdiv bigfloatone b
))
779 (a (mul -
1 n
) (cmul (- i
) (add n1 i
))))
780 ((> i
*expint-maxit
*)
782 (intl:gettext
"expintegral_e: continued fractions failed.")))
784 (setq b
(add b bigfloattwo
))
785 (setq d
(cdiv bigfloatone
(add (mul a d
) b
)))
786 (setq c
(add b
(cdiv a c
)))
790 (when (eq ($sign
(sub (cabs (sub e bigfloatone
)) *expint-eps
*))
792 (when *debug-expintegral
*
793 (setq *debug-expint-fracbfloatmaxit
*
794 (max *debug-expint-fracbfloatmaxit
* i
)))
795 (return (cmul h
(cpower bigfloat%e
(mul -
1 z
))))))))
797 ((or (and (numberp n
)
800 (= (nth-value 1 (truncate ($realpart n
))) 0))
803 (equal (sub (mul 2 ($fix n
)) (mul 2 n
))
805 ;; We have a Float or Bigfloat representation of positive integer.
806 ;; We call bfloat-expintegral-e.
807 (when *debug-expintegral
*
808 (format t
"frac-Bigfloat with integer ~A~%" n
))
809 (bfloat-expintegral-e ($fix
($realpart n
)) z
))
812 ;; At this point the parameter n is a real (not a float representation
813 ;; of an integer) or complex. We expand in a power series.
814 (when *debug-expintegral
*
815 (format t
"We expand in a power series.~%"))
816 (let* ((n1 (sub n bigfloatone
))
817 (n2 (sub bigfloatone n
))
818 (gm (take '(%gamma
) n2
))
819 (r (sub (cmul (cpower z n1
) gm
) (cdiv bigfloatone n2
)))
823 ((> i
*expint-maxit
*)
824 (merror (intl:gettext
"expintegral_e: series failed.")))
825 (setq f
(cmul (mul -
1 bigfloatone
) (cmul f
(cdiv z i
))))
826 (setq e
(cdiv (mul -
1 f
) (sub i n1
)))
828 (when (eq ($sign
(sub (cabs e
) (cmul (cabs r
) *expint-eps
*)))
830 (when *debug-expintegral
*
831 (setq *debug-expint-fracbfloatmaxit
*
832 (max *debug-expint-fracbfloatmaxit
* i
)))
835 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
837 ;;; Part 2: The implementation of the Exponential Integral E1
839 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
841 ;;; Exponential Integral E1 distributes over bags
843 (defprop %expintegral_e1
(mlist $matrix mequal
) distribute_over
)
845 ;;; Exponential Integral E1 has mirror symmetry,
846 ;;; but not on the real negative axis.
848 (defprop %expintegral_e1 conjugate-expintegral-e1 conjugate-function
)
850 (defun conjugate-expintegral-e1 (args)
851 (let ((z (first args
)))
852 (cond ((off-negative-real-axisp z
)
853 ;; Definitely not on the negative real axis for z. Mirror symmetry.
854 (take '(%expintegral_e1
) (take '($conjugate
) z
)))
856 ;; On the negative real axis or no information. Unsimplified.
857 (list '($conjugate simp
) (take '(%expintegral_e1
) z
))))))
859 ;;; Differentiation of Exponential Integral E1
861 (defprop %expintegral_e1
865 ((mexpt) $%e
((mtimes) -
1 x
))))
868 ;;; Integral of Exponential Integral E1
870 (defprop %expintegral_e1
872 ((mtimes) -
1 ((%expintegral_e
) 2 z
)))
875 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
877 ;;; We support a simplim%function. The function is looked up in simplimit and
878 ;;; handles specific values of the function.
880 (defprop %expintegral_e1 simplim%expintegral_e1 simplim%function
)
882 (defun simplim%expintegral_e1
(expr var val
)
883 ;; Look for the limit of the argument.
884 (let ((z (limit (cadr expr
) var val
'think
)))
886 ;; Handle an argument 0 at this place
890 ;; limit is inf from both sides
893 ;; All other cases are handled by the simplifier of the function.
894 (take '(%expintegral_e1
) z
)))))
896 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
898 ;;; Exponential Integral E1 is a simplifying function
899 (def-simplifier expintegral_e1
(arg)
901 ;; Check for special values
903 (alike1 arg
'((mtimes) -
1 $minf
)))
907 (intl:gettext
"expintegral_e1: expintegral_e1(~:M) is undefined.") arg
))
909 ;; Check for numerical evaluation
910 ((complex-float-numerical-eval-p arg
)
911 ;; For E1 we call En(z) with n=1 directly.
912 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
913 (complexify (expintegral-e 1 carg
))))
915 ((complex-bigfloat-numerical-eval-p arg
)
916 ;; For E1 we call En(z) with n=1 directly.
917 (let* (($ratprint nil
)
918 (carg (add ($bfloat
($realpart arg
))
919 (mul '$%i
($bfloat
($imagpart arg
)))))
920 (result (bfloat-expintegral-e 1 carg
)))
921 (add ($realpart result
)
922 (mul '$%i
($imagpart result
)))))
924 ;; Check argument simplifications and transformations
925 ((taylorize (mop form
) (second form
)))
928 (member $expintrep
*expintflag
* :test
#'eq
)
929 (not (eq $expintrep
'%expintegral_e1
)))
932 (take '(%gamma_incomplete
) 0 arg
))
934 (add (mul -
1 (take '(%expintegral_ei
) (mul -
1 arg
)))
936 (sub (take '(%log
) (mul -
1 arg
))
937 (take '(%log
) (mul -
1 (inv arg
)))))
938 (mul -
1 (take '(%log
) arg
))))
940 (add (mul -
1 (take '(%expintegral_li
) (power '$%e
(mul -
1 arg
))))
941 (mul -
1 (take '(%log
) arg
))
943 (sub (take '(%log
) (mul -
1 arg
))
944 (take '(%log
) (mul -
1 (inv arg
)))))))
946 (add (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i arg
)))
947 (mul -
1 (take '(%expintegral_ci
) (mul '$%i arg
)))
948 (take '(%log
) (mul '$%i arg
))
949 (mul -
1 (take '(%log
) arg
))))
951 (sub (take '(%expintegral_shi
) arg
)
952 (take '(%expintegral_chi
) arg
)))
959 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
961 ;;; Part 3: The implementation of the Exponential Integral Ei
963 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
965 ;;; Exponential Integral Ei distributes over bags
967 (defprop %expintegral_ei
(mlist $matrix mequal
) distribute_over
)
969 ;;; Exponential Integral Ei has mirror symmetry
971 (defprop %expintegral_ei t commutes-with-conjugate
)
973 ;;; Differentiation of Exponential Integral Ei
975 (defprop %expintegral_ei
977 ((mtimes) ((mexpt) x -
1) ((mexpt) $%e x
)))
980 ;;; Integral of Exponential Ei
982 (defprop %expintegral_ei
985 ((mtimes) -
1 ((mexpt) $%e x
))
986 ((mtimes) x
((%expintegral_ei
) x
))))
989 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
991 ;;; We support a simplim%function. The function is looked up in simplimit and
992 ;;; handles specific values of the function.
994 (defprop %expintegral_ei simplim%expintegral_ei simplim%function
)
996 (defun simplim%expintegral_ei
(expr var val
)
997 ;; Look for the limit of the arguments.
998 (let ((z (limit (cadr expr
) var val
'think
)))
1000 ;; Handle an argument 0 at this place
1006 ;; All other cases are handled by the simplifier of the function.
1007 (take '(%expintegral_ei
) z
)))))
1009 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1011 ;;; Exponential Integral Ei is a simplifying function
1012 (def-simplifier expintegral_ei
(arg)
1014 ;; Check special values
1017 (intl:gettext
"expintegral_ei: expintegral_ei(~:M) is undefined.")
1020 (alike1 arg
'((mtimes) -
1 $minf
)))
1022 ((or (eq arg
'$minf
)
1023 (alike1 arg
'((mtimes) -
1 $inf
)))
1025 ((or (alike1 arg
'((mtimes) $%i $inf
))
1026 (alike1 arg
'((mtimes) -
1 $%i $minf
)))
1028 ((or (alike1 arg
'((mtimes) $%i $minf
))
1029 (alike1 arg
'((mtimes) -
1 $%i $inf
)))
1030 (mul -
1 '$%i
'$%pi
))
1032 ;; Check numerical evaluation
1033 ((complex-float-numerical-eval-p arg
)
1034 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1035 (complexify (expintegral-ei carg
))))
1037 ((complex-bigfloat-numerical-eval-p arg
)
1038 (let* (($ratprint nil
)
1039 (carg (add ($bfloat
($realpart arg
))
1040 (mul '$%i
($bfloat
($imagpart arg
)))))
1041 (result (bfloat-expintegral-ei carg
)))
1042 (add ($realpart result
)
1043 (mul '$%i
($imagpart result
)))))
1045 ;; Check argument simplifications and transformations
1046 ((taylorize (mop form
) (second form
)))
1049 (member $expintrep
*expintflag
*)
1050 (not (eq $expintrep
'%expintegral_ei
)))
1053 (add (mul -
1 (take '(%gamma_incomplete
) 0 (mul -
1 arg
)))
1055 (sub (take '(%log
) arg
)
1056 (take '(%log
) (inv arg
))))
1057 (mul -
1 (take '(%log
) (mul -
1 arg
)))))
1059 (add (mul -
1 (take '(%expintegral_e1
) (mul -
1 arg
)))
1061 (sub (take '(%log
) arg
)
1062 (take '(%log
) (inv arg
))))
1063 (mul -
1 (take '(%log
) (mul -
1 arg
)))))
1065 (take '(%expintegral_li
) (power '$%e arg
)))
1067 (add (take '(%expintegral_ci
) (mul '$%i arg
))
1068 (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i arg
)))
1070 (sub (take '(%log
) (inv arg
))
1071 (take '(%log
) arg
)))
1072 (mul -
1 (take '(%log
) (mul '$%i arg
)))))
1074 (add (take '(%expintegral_chi
) arg
)
1075 (take '(%expintegral_shi
) arg
)
1077 (add (take '(%log
) (inv arg
))
1078 (take '(%log
) arg
)))))))
1083 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1084 ;;; Numerical evaluation of the Exponential Integral Ei(z):
1086 ;;; We use the following representation (see functions.wolfram.com):
1088 ;;; Ei(z) = -E1(-z) + 0.5*(log(z)-log(1/z))-log(-z)
1090 ;;; z is a CL Complex number. Because we evaluate for Complex values we have to
1091 ;;; take into account the complete Complex phase factors.
1092 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1094 (defun expintegral-ei (z)
1095 (+ (- (expintegral-e 1 (- z
)))
1096 ;; Carefully compute 1/2*(log(z)-log(1/z))-log(-z), using the
1097 ;; branch cuts that we want, not the one that Lisp wants.
1098 ;; (Mostly an issue with Lisps that support signed zeroes.)
1101 ;; Positive imaginary part. Add phase %i*%pi.
1102 (complex 0 (float pi
)))
1104 ;; Negative imaginary part. Add phase -%i*%pi.
1105 (complex 0 (- (float pi
))))
1107 ;; Positive real value. Add phase -%i*pi.
1108 (complex 0 (- (float pi
))))
1109 ;; Negative real value. No phase factor.
1112 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1113 ;;; We have not modified the algorithm for Bigfloat numbers. It is only
1114 ;;; generalized for Bigfloats. The calcualtion of the complex phase factor
1115 ;;; can be simplified to conditions about the sign of the realpart and
1116 ;;; imagpart. We leave this for further work to optimize the speed of the
1118 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1120 (defun bfloat-expintegral-ei (z)
1121 (let ((mz (mul -
1 z
)))
1122 (add (cmul (mul -
1 bigfloatone
)
1123 (bfloat-expintegral-e 1 mz
))
1124 (sub (cmul (div bigfloatone
2)
1125 (sub (take '(%log
) z
)
1126 (take '(%log
) (cdiv bigfloatone z
))))
1127 (take '(%log
) mz
)))))
1129 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1131 ;;; Part 4: The implementation of the Logarithmic integral li(z)
1133 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1135 ;;; Exponential Integral Li distributes over bags
1137 (defprop %expintegral_li
(mlist $matrix mequal
) distribute_over
)
1139 ;;; Exponential Integral Li has mirror symmetry,
1140 ;;; but not on the real negative axis.
1142 (defprop %expintegral_li conjugate-expintegral-li conjugate-function
)
1144 (defun conjugate-expintegral-li (args)
1145 (let ((z (first args
)))
1146 (cond ((off-negative-real-axisp z
)
1147 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1148 (take '(%expintegral_li
) (take '($conjugate
) z
)))
1150 ;; On the negative real axis or no information. Unsimplified.
1151 (list '($conjugate simp
) (take '(%expintegral_li
) z
))))))
1153 ;;; Differentiation of Exponential Integral Li
1155 (defprop %expintegral_li
1157 ((mtimes) ((mexpt) ((%log
) x
) -
1)))
1160 ;;; Integral of Exponential Li
1162 (defprop %expintegral_li
1165 ((mtimes) x
((%expintegral_li
) x
))
1166 ((mtimes) -
1 ((%expintegral_ei
) ((mtimes) 2 ((%log
) x
))))))
1169 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1171 ;;; We support a simplim%function. The function is looked up in simplimit and
1172 ;;; handles specific values of the function.
1174 (defprop %expintegral_li simplim%expintegral_li simplim%function
)
1176 (defun simplim%expintegral_li
(expr var val
)
1177 ;; Look for the limit of the argument.
1178 (let ((z (limit (cadr expr
) var val
'think
)))
1180 ;; Handle an argument 1 at this place
1183 ;; All other cases are handled by the simplifier of the function.
1184 (take '(%expintegral_li
) z
)))))
1186 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1188 ;;; Exponential Integral Li is a simplifying function
1189 (def-simplifier expintegral_li
(arg)
1194 (intl:gettext
"expintegral_li: expintegral_li(~:M) is undefined.") arg
))
1196 (alike1 arg
'((mtimes) -
1 $minf
)))
1198 ((eq arg
'$infinity
) '$infinity
)
1200 ((complex-float-numerical-eval-p arg
)
1201 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1202 (complexify (expintegral-li carg
))))
1204 ((complex-bigfloat-numerical-eval-p arg
)
1205 (let* (($ratprint nil
)
1206 (carg (add ($bfloat
($realpart arg
))
1207 (mul '$%i
($bfloat
($imagpart arg
)))))
1208 (result (bfloat-expintegral-li carg
)))
1209 (add (mul '$%i
($imagpart result
))
1210 ($realpart result
))))
1212 ;; Check for argument simplifications and transformations
1213 ((taylorize (mop form
) (second form
)))
1216 (member $expintrep
*expintflag
*)
1217 (not (eq $expintrep
'%expintegral_li
)))
1218 (let ((logarg (take '(%log
) arg
)))
1221 (add (mul -
1 (take '(%gamma_incomplete
) 0 (mul -
1 logarg
)))
1223 (sub (take '(%log
) logarg
)
1224 (take '(%log
) (inv logarg
))))
1225 (mul -
1 (take '(%log
) (mul -
1 logarg
)))))
1227 (add (mul -
1 (take '(%expintegral_e1
) (mul -
1 logarg
)))
1229 (sub (take '(%log
) logarg
)
1230 (take '(%log
) (inv logarg
))))
1231 (mul -
1 (take '(%log
) (mul -
1 logarg
)))))
1233 ($expintegral_ei logarg
))
1235 (add (take '(%expintegral_ci
) (mul '$%i logarg
))
1236 (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i logarg
)))
1238 (sub (take '(%log
) (inv logarg
))
1239 (take '(%log
) logarg
)))
1240 (mul -
1 (take '(%log
) (mul '$%i logarg
)))))
1242 (add (take '(%expintegral_chi
) logarg
)
1243 (take '(%expintegral_shi
) logarg
)
1245 (add (take '(%log
) (inv logarg
))
1246 (take '(%log
) logarg
))))))))
1251 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1252 ;;; Numerical evaluation of the Expintegral Li
1254 ;;; We use the representation:
1256 ;;; Li(z) = Ei(log(z))
1257 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1259 (defun expintegral-li (z)
1260 (expintegral-ei (log z
)))
1262 (defun bfloat-expintegral-li (z)
1263 (bfloat-expintegral-ei ($log z
)))
1265 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1267 ;;; Part 5: The implementation of the Exponential Integral Si
1269 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1271 ;;; Exponential Integral Si distributes over bags
1273 (defprop %expintegral_si
(mlist $matrix mequal
) distribute_over
)
1275 ;;; Exponential Integral Si has mirror symmetry
1277 (defprop %expintegral_si t commutes-with-conjugate
)
1279 ;;; Exponential Integral Si is a odd function
1281 (defprop %expintegral_si odd-function-reflect reflection-rule
)
1283 ;;; Differentiation of Exponential Integral Si
1285 (defprop %expintegral_si
1287 ((mtimes) ((%sin
) x
) ((mexpt) x -
1)))
1290 ;;; Integral of Exponential Si
1292 (defprop %expintegral_si
1296 ((mtimes) x
((%expintegral_si
) x
))))
1299 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1301 ;;; We support a simplim%function.
1303 (defprop %expintegral_si simplim%expintegral_si simplim%function
)
1305 (defun simplim%expintegral_si
(expr var val
)
1306 ;; Look for the limit of the argument.
1307 (let ((z (limit (cadr expr
) var val
'think
)))
1308 ;; All cases are handled by the simplifier of the function.
1309 (take '(%expintegral_si
) z
)))
1311 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1313 ;;; Exponential Integral Si is a simplifying function
1314 (def-simplifier expintegral_si
(arg)
1316 ;; Check for special values
1319 (alike1 arg
'((mtimes) -
1 $minf
)))
1321 ((or (eq arg
'$minf
)
1322 (alike1 arg
'((mtimes) -
1 $inf
)))
1323 (mul -
1 (div '$%pi
2)))
1325 ;; Check for numerical evaluation
1326 ((complex-float-numerical-eval-p arg
)
1327 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1328 (complexify (expintegral-si carg
))))
1330 ((complex-bigfloat-numerical-eval-p arg
)
1331 (let* (($ratprint nil
)
1332 (carg (add ($bfloat
($realpart arg
))
1333 (mul '$%i
($bfloat
($imagpart arg
)))))
1334 (result (bfloat-expintegral-si carg
)))
1335 (add (mul '$%i
($imagpart result
))
1336 ($realpart result
))))
1338 ;; Check for argument simplifications and transformations
1339 ((taylorize (mop form
) (second form
)))
1340 ((apply-reflection-simp (mop form
) arg $trigsign
))
1343 (member $expintrep
*expintflag
*)
1344 (not (eq $expintrep
'$expintegral_trig
)))
1348 (add (take '(%gamma_incomplete
) 0 (mul -
1 '$%i arg
))
1349 (mul -
1 (take '(%gamma_incomplete
) 0 (mul '$%i arg
)))
1350 (take '(%log
) (mul -
1 '$%i arg
))
1351 (mul -
1 (take '(%log
) (mul '$%i arg
))))))
1354 (add (take '(%expintegral_e1
) (mul -
1 '$%i arg
))
1355 (mul -
1 (take '(%expintegral_e1
) (mul '$%i arg
)))
1356 (take '(%log
) (mul -
1 '$%i arg
))
1357 (mul -
1 (take '(%log
) (mul '$%i arg
))))))
1361 (sub (take '(%expintegral_ei
) (mul -
1 '$%i arg
))
1362 (take '(%expintegral_ei
) (mul '$%i arg
))))
1363 (take '(%log
) (div '$%i arg
))
1364 (mul -
1 (take '(%log
) (mul -
1 (div '$%i arg
))))
1365 (mul -
1 (take '(%log
) (mul -
1 '$%i arg
)))
1366 (take '(%log
) (mul '$%i arg
)))))
1368 (mul (inv (mul 2 '$%i
))
1369 (add (take '(%expintegral_li
) (power '$%e
(mul '$%i arg
)))
1371 (take '(%expintegral_li
)
1372 (power '$%e
(mul -
1 '$%e arg
))))
1374 (take '(%signum
) ($realpart arg
))))))
1376 (mul -
1 '$%i
(take '(%expintegral_shi
) (mul '$%i arg
))))))
1381 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1382 ;;; Numerical evaluation of the Exponential Integral Si
1384 ;;; We use the representation:
1386 ;;; Si(z) = %i/2 * (E1(-%i*z) - E1(*%i*z) + log(%i*z) - log(-%i*z))
1388 ;;; For the Sin, Cos, Sinh and Cosh Exponential Integrals we have to call the
1389 ;;; numerical evaluation twice. In principle we could use a direct expansion
1390 ;;; in a power series or continued fractions to optimize the speed of the code.
1391 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1393 (defun expintegral-si (z)
1394 (let ((z (coerce z
'(complex flonum
))))
1396 (+ (expintegral-e 1 (* (complex 0 -
1) z
))
1397 (- (expintegral-e 1 (* (complex 0 1) z
)))
1398 (log (* (complex 0 -
1) z
))
1399 (- (log (* (complex 0 1) z
)))))))
1401 (defun bfloat-expintegral-si (z)
1402 (let ((z*%i
(cmul '$%i z
))
1403 (mz*%i
(cmul (mul -
1 '$%i
) z
)))
1407 (bfloat-expintegral-e 1 mz
*%i
)
1408 (mul -
1 (bfloat-expintegral-e 1 z
*%i
))
1410 (mul -
1 ($log z
*%i
))))))
1412 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1414 ;;; Part 6: The implementation of the Exponential Integral Shi
1416 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1418 ;;; Exponential Integral Shi distributes over bags
1420 (defprop %expintegral_shi
(mlist $matrix mequal
) distribute_over
)
1422 ;;; Exponential Integral Shi has mirror symmetry
1424 (defprop %expintegral_si t commutes-with-conjugate
)
1426 ;;; Exponential Integral Shi is a odd function
1428 (defprop %expintegral_si odd-function-reflect reflection-rule
)
1430 ;;; Differentiation of Exponential Integral Shi
1432 (defprop %expintegral_shi
1434 ((mtimes) ((%sinh
) x
) ((mexpt) x -
1)))
1437 ;;; Integral of Exponential Shi
1439 (defprop %expintegral_shi
1442 ((mtimes) -
1 ((%cosh
) x
))
1443 ((mtimes) x
((%expintegral_shi
) x
))))
1446 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1448 ;;; We support a simplim%function. The function is looked up in simplimit and
1449 ;;; handles specific values of the function.
1451 (defprop %expintegral_shi simplim%expintegral_shi simplim%function
)
1453 (defun simplim%expintegral_shi
(expr var val
)
1454 ;; Look for the limit of the argument.
1455 (let ((z (limit (cadr expr
) var val
'think
)))
1457 ;; Handle infinities at this place
1463 ;; All other cases are handled by the simplifier of the function.
1464 (take '(%expintegral_shi
) z
)))))
1466 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1468 ;;; Exponential Integral Shi is a simplifying function
1469 (def-simplifier expintegral_shi
(arg)
1471 ;; Check for special values
1473 ((or (alike1 arg
'((mtimes) $%i $inf
))
1474 (alike1 arg
'((mtimes) -
1 $%i $minf
)))
1475 (div (mul '$%i
'$%pi
) 2))
1476 ((or (alike1 arg
'((mtimes) $%i $minf
))
1477 (alike1 arg
'((mtimes) -
1 $%i $inf
)))
1478 (div (mul -
1 '$%i
'$%pi
) 2))
1480 ;; Check for numrical evaluation
1481 ((float-numerical-eval-p arg
)
1482 (realpart (expintegral-shi arg
)))
1484 ((complex-float-numerical-eval-p arg
)
1485 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1486 (complexify (expintegral-shi carg
))))
1488 ((complex-bigfloat-numerical-eval-p arg
)
1489 (let* (($ratprint nil
)
1490 (carg (add ($bfloat
($realpart arg
))
1491 (mul '$%i
($bfloat
($imagpart arg
)))))
1492 (result (bfloat-expintegral-shi carg
)))
1493 (add (mul '$%i
($imagpart result
))
1494 ($realpart result
))))
1496 ;; Check for argument simplifications and transformations
1497 ((taylorize (mop form
) (second form
)))
1498 ((apply-reflection-simp (mop form
) arg $trigsign
))
1501 (member $expintrep
*expintflag
*)
1502 (not (eq $expintrep
'$expintegral_hyp
)))
1506 (add (take '(%gamma_incomplete
) 0 arg
)
1507 (mul -
1 (take '(%gamma_incomplete
) 0 (mul -
1 arg
)))
1508 (mul -
1 (take '(%log
) (mul -
1 arg
)))
1509 (take '(%log
) arg
))))
1512 (add (take '(%expintegral_e1
) arg
)
1513 (mul -
1 (take '(%expintegral_e1
) (mul -
1 arg
)))
1514 (mul -
1 (take '(%log
) (mul -
1 arg
)))
1515 (take '(%log
) arg
))))
1519 (sub (take '(%expintegral_ei
) arg
)
1520 (take '(%expintegral_ei
) (mul -
1 arg
))))
1521 (take '(%log
) (inv arg
))
1522 (mul -
1 (take '(%log
) (mul -
1 (inv arg
))))
1523 (take '(%log
) (mul -
1 arg
))
1524 (mul -
1 (take '(%log
) arg
)))))
1527 (sub (take '(%expintegral_li
) (power '$%e arg
))
1528 (take '(%expintegral_li
) (power '$%e
(mul -
1 arg
)))))
1529 (mul (div (mul '$%i
'$%pi
) -
2)
1530 (take '(%signum
) ($imagpart arg
)))))
1532 (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i arg
))))))
1537 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1538 ;;; Numerical evaluation of the Exponential Integral Shi
1540 ;;; We use the representation:
1542 ;;; Shi(z) = 1/2 * (E1(z) - E1(-z) - log(-z) + log(z))
1544 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1546 (defun expintegral-shi (z)
1551 (- (expintegral-e 1 (- z
)))
1555 (defun bfloat-expintegral-shi (z)
1556 (let ((mz (mul -
1 z
)))
1560 (bfloat-expintegral-e 1 z
)
1561 (mul -
1 (bfloat-expintegral-e 1 mz
))
1565 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1567 ;;; Part 7: The implementation of the Exponential Integral Ci
1569 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1571 ;;; Exponential Integral Ci distributes over bags
1573 (defprop %expintegral_ci
(mlist $matrix mequal
) distribute_over
)
1575 ;;; Exponential Integral Ci has mirror symmetry,
1576 ;;; but not on the real negative axis.
1578 (defprop %expintegral_ci conjugate-expintegral-ci conjugate-function
)
1580 (defun conjugate-expintegral-ci (args)
1581 (let ((z (first args
)))
1582 (cond ((off-negative-real-axisp z
)
1583 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1584 (take '(%expintegral_ci
) (take '($conjugate
) z
)))
1586 ;; On the negative real axis or no information. Unsimplified.
1587 (list '($conjugate simp
) (take '(%expintegral_ci
) z
))))))
1589 ;;; Differentiation of Exponential Integral Ci
1591 (defprop %expintegral_ci
1593 ((mtimes) ((%cos
) x
) ((mexpt) x -
1)))
1596 ;;; Integral of Exponential Ci
1598 (defprop %expintegral_ci
1601 ((mtimes) x
((%expintegral_ci
) x
))
1602 ((mtimes) -
1 ((%sin
) x
))))
1605 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1607 ;;; We support a simplim%function. The function is looked up in simplimit and
1608 ;;; handles specific values of the function.
1610 (defprop %expintegral_ci simplim%expintegral_ci simplim%function
)
1612 (defun simplim%expintegral_ci
(expr var val
)
1613 ;; Look for the limit of the argument.
1614 (let ((z (limit (cadr expr
) var val
'think
)))
1616 ;; Handle an argument 0 at this place
1622 ;; All other cases are handled by the simplifier of the function.
1623 (take '(%expintegral_ci
) z
)))))
1625 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1627 ;;; Exponential Integral Ci is a simplifying function
1628 (def-simplifier expintegral_ci
(arg)
1630 ;; Check for special values
1633 (intl:gettext
"expintegral_ci: expintegral_ci(~:M) is undefined.") arg
))
1635 (alike1 arg
'((mtimes) -
1 $minf
)))
1637 ((or (eq arg
'$minf
)
1638 (alike1 arg
'((mtimes) -
1 $inf
)))
1641 ;; Check for numerical evaluation
1642 ((complex-float-numerical-eval-p arg
)
1643 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1644 (complexify (expintegral-ci carg
))))
1646 ((complex-bigfloat-numerical-eval-p arg
)
1647 (let* (($ratprint nil
)
1648 (carg (add ($bfloat
($realpart arg
))
1649 (mul '$%i
($bfloat
($imagpart arg
)))))
1650 (result (bfloat-expintegral-ci carg
)))
1651 (add (mul '$%i
($imagpart result
))
1652 ($realpart result
))))
1654 ;; Check for argument simplifications and transformations
1655 ((taylorize (mop form
) (second form
)))
1658 (member $expintrep
*expintflag
*)
1659 (not (eq $expintrep
'$expintegral_trig
)))
1662 (sub (take '(%log
) arg
)
1664 (add (take '(%gamma_incomplete
) 0 (mul -
1 '$%i arg
))
1665 (take '(%gamma_incomplete
) 0 (mul '$%i arg
))
1666 (take '(%log
) (mul -
1 '$%i arg
))
1667 (take '(%log
) (mul '$%i arg
))))))
1670 (add (take '(%expintegral_e1
) (mul -
1 '$%i arg
))
1671 (take '(%expintegral_e1
) (mul '$%i arg
)))
1672 (take '(%log
) (mul -
1 '$%i arg
))
1673 (take '(%log
) (mul '$%i arg
)))
1674 (take '(%log
) arg
)))
1678 (add (take '(%expintegral_ei
) (mul -
1 '$%i arg
))
1679 (take '(%expintegral_ei
) (mul '$%i arg
))))
1680 (take '(%log
) (div '$%i arg
))
1681 (take '(%log
) (mul -
1 '$%i
(inv arg
)))
1682 (mul -
1 (take '(%log
) (mul -
1 '$%i arg
)))
1683 (mul -
1 (take '(%log
) (mul '$%i arg
)))))
1684 (take '(%log
) arg
)))
1687 (add (take '(%expintegral_li
)
1688 (power '$%e
(mul -
1 '$%i arg
)))
1689 (take '(%expintegral_li
)
1690 (power '$%e
(mul '$%i arg
)))))
1691 (mul (div (mul '$%i
'$%pi
) 2)
1692 (take '(%signum
) ($imagpart arg
)))
1693 (sub 1 (take '(%signum
) ($realpart arg
)))))
1695 (add (take '(%expintegral_chi
) (mul '$%i arg
))
1696 (mul -
1 (take '(%log
) (mul '$%i arg
)))
1697 (take '(%log
) arg
)))))
1702 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1703 ;;; Numerical evaluation of the Exponential Integral Ci
1705 ;;; We use the representation:
1707 ;;; Ci(z) = -1/2 * (E1(-%i*z) + E1(%i*z) + log(-%i*z) + log(%i*z)) + log(z)
1709 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1711 (defun expintegral-ci (z)
1712 (let ((z (coerce z
'(complex flonum
))))
1714 (+ (expintegral-e 1 (* (complex 0 -
1) z
))
1715 (expintegral-e 1 (* (complex 0 1) z
))
1716 (log (* (complex 0 -
1) z
))
1717 (log (* (complex 0 1) z
))))
1720 (defun bfloat-expintegral-ci (z)
1721 (let ((z*%i
(cmul '$%i z
))
1722 (mz*%i
(cmul (mul -
1 '$%i
) z
)))
1727 (bfloat-expintegral-e 1 mz
*%i
)
1728 (bfloat-expintegral-e 1 z
*%i
)
1733 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1735 ;;; Part 8: The implementation of the Exponential Integral Chi
1737 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1739 ;;; Exponential Integral Chi distributes over bags
1741 (defprop %expintegral_chi
(mlist $matrix mequal
) distribute_over
)
1743 ;;; Exponential Integral Chi has mirror symmetry,
1744 ;;; but not on the real negative axis.
1746 (defprop %expintegral_chi conjugate-expintegral-chi conjugate-function
)
1748 (defun conjugate-expintegral-chi (args)
1749 (let ((z (first args
)))
1750 (cond ((off-negative-real-axisp z
)
1751 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1752 (take '(%expintegral_chi
) (take '($conjugate
) z
)))
1754 ;; On the negative real axis or no information. Unsimplified.
1755 (list '($conjugate simp
) (take '(%expintegral_chi
) z
))))))
1757 ;;; Differentiation of Exponential Integral Chi
1759 (defprop %expintegral_chi
1761 ((mtimes) ((%cosh
) x
) ((mexpt) x -
1)))
1764 ;;; Integral of Exponential Chi
1766 (defprop %expintegral_chi
1769 ((mtimes) x
((%expintegral_chi
) x
))
1770 ((mtimes) -
1 ((%sinh
) x
))))
1773 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1775 ;;; We support a simplim%function. The function is looked up in simplimit and
1776 ;;; handles specific values of the function.
1778 (defprop %expintegral_chi simplim%expintegral_chi simplim%function
)
1780 (defun simplim%expintegral_chi
(expr var val
)
1781 ;; Look for the limit of the argument.
1782 (let ((z (limit (cadr expr
) var val
'think
)))
1784 ;; Handle an argument 0 at this place
1793 ;; All other cases are handled by the simplifier of the function.
1794 (take '(%expintegral_chi
) z
)))))
1796 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1798 ;;; Exponential Integral Chi is a simplifying function
1799 (def-simplifier expintegral_chi
(arg)
1801 ;; Check for special values
1803 ;; First check for zero argument. Throw Maxima error.
1805 (intl:gettext
"expintegral_chi: expintegral_chi(~:M) is undefined.")
1807 ((or (alike1 arg
'((mtimes) $%i $inf
))
1808 (alike1 arg
'((mtimes) -
1 $%i $minf
)))
1809 (div (mul '$%pi
'$%i
) 2))
1810 ((or (alike1 arg
'((mtimes) $%i $minf
))
1811 (alike1 arg
'((mtimes) -
1 $%i $inf
)))
1812 (div (mul -
1 '$%pi
'$%i
) 2))
1814 ;; Check for numerical evaluation
1815 ((complex-float-numerical-eval-p arg
)
1816 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1817 (complexify (expintegral-chi carg
))))
1819 ((complex-bigfloat-numerical-eval-p arg
)
1820 (let* (($ratprint nil
)
1821 (carg (add ($bfloat
($realpart arg
))
1822 (mul '$%i
($bfloat
($imagpart arg
)))))
1823 (result (bfloat-expintegral-chi carg
)))
1824 (add (mul '$%i
($imagpart result
))
1825 ($realpart result
))))
1827 ;; Check for argument simplifications and transformations
1828 ((taylorize (mop form
) (second form
)))
1831 (member $expintrep
*expintflag
*)
1832 (not (eq $expintrep
'$expintegral_hyp
)))
1836 (add (take '(%gamma_incomplete
) 0 (mul -
1 arg
))
1837 (take '(%gamma_incomplete
) 0 arg
)
1838 (take '(%log
) (mul -
1 arg
))
1839 (mul -
1 (take '(%log
) arg
)))))
1842 (add (take '(%expintegral_e1
) (mul -
1 arg
))
1843 (take '(%expintegral_e1
) arg
)
1844 (take '(%log
) (mul -
1 arg
))
1845 (mul -
1 (take '(%log
) arg
)))))
1849 (add (take '(%expintegral_ei
) (mul -
1 arg
))
1850 (take '(%expintegral_ei
) arg
)))
1851 (take '(%log
) (inv arg
))
1852 (take '(%log
) (mul -
1 (inv arg
)))
1853 (mul -
1 (take '(%log
) (mul -
1 arg
)))
1854 (mul 3 (take '(%log
) arg
)))))
1857 (add (take '(%expintegral_li
) (power '$%e
(mul -
1 arg
)))
1858 (take '(%expintegral_li
) (power '$%e arg
))))
1859 (mul (div (mul '$%i
'$%pi
) 2)
1860 (take '(%signum
) ($imagpart arg
)))
1862 (add (take '(%log
) (inv arg
))
1863 (take '(%log
) arg
)))))
1865 (add (take '(%expintegral_ci
) (mul '$%i arg
))
1867 (mul -
1 (take '(%log
) (mul '$%i arg
)))))))
1872 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1873 ;;; Numerical evaluation of the Exponential Integral Ci
1875 ;;; We use the representation:
1877 ;;; Chi(z) = -1/2 * (E1(-z) + E1(z) + log(-z) - log(z))
1879 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1881 (defun expintegral-chi (z)
1886 (expintegral-e 1 (- z
))
1890 (defun bfloat-expintegral-chi (z)
1891 (let ((mz (mul -
1 z
)))
1895 (bfloat-expintegral-e 1 z
)
1896 (bfloat-expintegral-e 1 mz
)
1898 (mul -
1 ($log z
))))))
1900 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1901 ;; Moved from bessel.lisp 2008-12-11. Consider deleting it.
1903 ;; Exponential integral E1(x). The Cauchy principal value is used for
1905 (defmfun $expint
(x)
1907 (values (slatec:de1
(float x
))))
1909 (list '($expint simp
) x
))))