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 Exponential
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 does not converge within *expint-maxit* steps a Maxima
497 ;;; The algorithm is based on techniques
498 ;;; described in Numerical Recipes, 2nd Ed.
499 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
501 ;;; Constants to terminate the numerical evaluation
503 ;;; The accuracy *expint-eps* is fixed to 1.0e-15 for double float calculations.
504 ;;; The variable is declared global, so we can later give the Maxima User access
505 ;;; to the variable. The routine for Bigfloat numerical evaluation change this
506 ;;; value to the desired precision of the global $fpprec.
507 ;;; The maximum number of iterations is arbitrary set to 1000. For Bigfloat
508 ;;; evaluation this number is for very Big numbers too small.
510 ;;; The maximum iterations counted for the test file rtest-expintegral.mac are
511 ;;; 101 for Complex Flonum and 1672 for Complex Bigfloat evaluation.
513 (defvar *expint-eps
* 1.0e-15)
514 (defvar *expint-maxit
* 1000)
516 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
518 (defun expintegral-e (n z
)
519 (declare (type integer n
))
520 (let ((*expint-eps
* *expint-eps
*)
521 (*expint-maxit
* *expint-maxit
*)
522 ;; Add (complex) 0 to get rid of any signed zeroes, and make z
523 ;; be a complex number.
524 (z (+ (coerce 0 '(complex flonum
)) z
)))
525 (declare (type (complex flonum
) z
))
527 (when *debug-expintegral
*
528 (format t
"~&EXPINTEGRAL-E called with:~%")
529 (format t
"~& : n = ~A~%" n
)
530 (format t
"~& : z = ~A~%" z
))
533 ((or (and (> (abs z
) 2.0) (< (abs (phase z
)) (* pi
0.9)))
534 ;; (abs z)>2.0 is necessary since there is a point
535 ;; -1.700598-0.612828*%i which 1<(abs z)<2, phase z < 0.9pi and
536 ;; still c-f expansion does not converge.
537 (and (>= (realpart z
) 0) (> (abs z
) 1.0)))
538 ;; We expand in continued fractions.
539 (when *debug-expintegral
*
540 (format t
"~&We expand in continued fractions.~%"))
542 (c (/ 1.0 (* *expint-eps
* *expint-eps
*)))
548 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
549 ((> i
*expint-maxit
*)
551 (intl:gettext
"expintegral_e: continued fractions failed.")))
554 (setq d
(/ 1.0 (+ (* a d
) b
)))
555 (setq c
(+ b
(/ a c
)))
559 (when (< (abs (- e
1.0)) *expint-eps
*)
560 (when *debug-expintegral
*
561 (setq *debug-expint-maxit
* (max *debug-expint-maxit
* i
)))
562 (return (* h
(exp (- z
))))))))
564 ;; We expand in a power series.
565 (when *debug-expintegral
*
566 (format t
"~&We expand in a power series.~%"))
568 (euler (mget '$%gamma
'$numer
))
569 (r (if (= n1
0) (- (- euler
) (log z
)) (/ 1.0 n1
)))
573 ((> i
*expint-maxit
*)
574 (merror (intl:gettext
"expintegral_e: series failed.")))
575 (setq f
(* -
1 f
(/ z i
)))
578 (let ((psi (- euler
)))
580 (setq psi
(+ psi
(/ 1.0 (+ ii
1)))))
581 (setq e
(* f
(- psi
(log z
))))))
583 (setq e
(/ (- f
) (- i n1
)))))
585 (when (< (abs e
) (* (abs r
) *expint-eps
*))
586 (when *debug-expintegral
*
587 (setq *debug-expint-maxit
* (max *debug-expint-maxit
* i
)))
590 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
591 ;;; Numerical evaluation for a real or complex parameter.
592 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
594 (defun frac-expintegral-e (n z
)
595 (declare (type (complex flonum
) n
)
596 (type (complex flonum
) z
))
598 (let ((*expint-eps
* *expint-eps
*)
599 (*expint-maxit
* *expint-maxit
*))
601 (when *debug-expintegral
*
602 (format t
"~&FRAC-EXPINTEGRAL-E called with:~%")
603 (format t
"~& : n = ~A~%" n
)
604 (format t
"~& : z = ~A~%" z
))
607 ((and (> (realpart z
) 0) (> (abs z
) 1.0))
608 ;; We expand in continued fractions.
609 (when *debug-expintegral
*
610 (format t
"~&We expand in continued fractions.~%"))
612 (c (/ 1.0 (* *expint-eps
* *expint-eps
*)))
618 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
619 ((> i
*expint-maxit
*)
621 (intl:gettext
"expintegral_e: continued fractions failed.")))
624 (setq d
(/ 1.0 (+ (* a d
) b
)))
625 (setq c
(+ b
(/ a c
)))
629 (when (< (abs (- e
1.0)) *expint-eps
*)
630 (when *debug-expintegral
*
631 (setq *debug-expint-fracmaxit
* (max *debug-expint-fracmaxit
* i
)))
632 (return (* h
(exp (- z
))))))))
634 ((and (= (imagpart n
) 0)
636 (= (nth-value 1 (truncate (realpart n
))) 0))
637 ;; We have a positive integer n or an float representation of an
638 ;; integer. We call expintegral-e which does this calculation.
639 (when *debug-expintegral
*
640 (format t
"~&We call expintegral-e.~%"))
641 (expintegral-e (truncate (realpart n
)) z
))
644 ;; At this point the parameter n is a real (not an float representation
645 ;; of an integer) or complex. We expand in a power series.
646 (when *debug-expintegral
*
647 (format t
"~&We expand in a power series.~%"))
649 ;; It would be possible to call the numerical implementation
650 ;; gamm-lanczos directly. But then the code would depend on the
651 ;; details of the implementation.
652 (gm (let ((tmp (take '(%gamma
) (complexify (- 1 n
)))))
653 (complex ($realpart tmp
) ($imagpart tmp
))))
654 (r (- (* (expt z n1
) gm
) (/ 1.0 (- 1 n
))))
658 ((> i
*expint-maxit
*)
659 (merror (intl:gettext
"expintegral_e: series failed.")))
660 (setq f
(* -
1 f
(/ z
(float i
))))
661 (setq e
(/ (- f
) (- (float i
) n1
)))
663 (when (< (abs e
) (* (abs r
) *expint-eps
*))
664 (when *debug-expintegral
*
665 (setq *debug-expint-fracmaxit
* (max *debug-expint-fracmaxit
* i
)))
668 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
669 ;;; Helper functions for Bigfloat numerical evaluation.
670 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
672 (defun cmul (x y
) ($rectform
(mul x y
)))
674 (defun cdiv (x y
) ($rectform
(div x y
)))
676 (defun cpower (x y
) ($rectform
(power x y
)))
678 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
679 ;;; We have not changed the above algorithm, but generalized it to handle
680 ;;; complex and real Bigfloat numbers. By carefully examination of the
681 ;;; algorithm some of the additional calls to $rectform can be eliminated.
682 ;;; But the algorithm works and so we leave the extra calls for later work
684 ;;; The accuracy of the result is determined by *expint-eps*. The value is
685 ;;; chosen to correspond to the value of $fpprec. We don't give any extra
686 ;;; digits to fpprec, so we loose 1 to 2 digits of precision.
687 ;;; One problem is to chose a sufficient big *expint-maxit*.
688 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
690 (defun bfloat-expintegral-e (n z
)
691 (let ((*expint-eps
* (power ($bfloat
10.0) (- $fpprec
)))
692 (*expint-maxit
* 5000) ; arbitrarily chosen, we need a better choice
693 (bigfloattwo (add bigfloatone bigfloatone
))
694 (bigfloat%e
($bfloat
'$%e
))
695 (bigfloat%gamma
($bfloat
'$%gamma
))
696 (flz (complex ($float
($realpart z
)) ($float
($imagpart z
)))))
698 (when *debug-expintegral
*
699 (format t
"~&BFLOAT-EXPINTEGRAL-E called with:~%")
700 (format t
"~& : n = ~A~%" n
)
701 (format t
"~& : z = ~A~%" flz
))
704 ((or (and (> (abs flz
) 2) (< (abs (phase flz
)) (* pi
0.9)))
705 ;; The same condition as you see in expintegral-e()
706 (and (>= (realpart flz
) 0) (> (abs flz
) 1.0)))
707 ;; We expand in continued fractions.
708 (when *debug-expintegral
*
709 (format t
"~&We expand in continued fractions.~%"))
711 (c (div bigfloatone
(mul *expint-eps
* *expint-eps
*)))
712 (d (cdiv bigfloatone b
))
717 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
718 ((> i
*expint-maxit
*)
720 (intl:gettext
"expintegral_e: continued fractions failed.")))
722 (setq b
(add b bigfloattwo
))
723 (setq d
(cdiv bigfloatone
(add (mul a d
) b
)))
724 (setq c
(add b
(cdiv a c
)))
728 (when (eq ($sign
(sub (cabs (sub e bigfloatone
)) *expint-eps
*))
730 (when *debug-expintegral
*
731 (setq *debug-expint-bfloatmaxit
*
732 (max *debug-expint-bfloatmaxit
* i
)))
733 (return (cmul h
(cpower bigfloat%e
(mul -
1 z
))))))))
735 ;; We expand in a power series.
736 (when *debug-expintegral
*
737 (format t
"~&We expand in a power series.~%"))
739 (meuler (mul -
1 bigfloat%gamma
))
740 (r (if (= n1
0) (sub meuler
($log z
)) (div bigfloatone n1
)))
744 ((> i
*expint-maxit
*)
745 (merror (intl:gettext
"expintegral_e: series failed.")))
746 (setq f
(mul -
1 (cmul f
(cdiv z i
))))
751 (setq psi
(add psi
(cdiv bigfloatone
(+ ii
1)))))
752 (setq e
(cmul f
(sub psi
($log z
))))))
754 (setq e
(cdiv (mul -
1 f
) (- i n1
)))))
756 (when (eq ($sign
(sub (cabs e
) (cmul (cabs r
) *expint-eps
*)))
758 (when *debug-expintegral
*
759 (setq *debug-expint-bfloatmaxit
*
760 (max *debug-expint-bfloatmaxit
* i
)))
763 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
764 ;;; Numerical Bigfloat evaluation for a real (Bigfloat) parameter.
765 ;;; The algorithm would work for a Complex Bigfloat parameter too. But we
766 ;;; need the values of Gamma for Complex Bigfloats. This is at this time (2008)
767 ;;; not implemented in Maxima.
768 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
770 (defun frac-bfloat-expintegral-e (n z
)
771 (let ((*expint-eps
* (power ($bfloat
10.0) (- $fpprec
)))
772 (*expint-maxit
* 5000) ; arbitrarily chosen, we need a better choice
773 (bigfloattwo (add bigfloatone bigfloatone
))
774 (bigfloat%e
($bfloat
'$%e
))
775 (bigfloat%gamma
($bfloat
'$%gamma
)))
777 (when *debug-expintegral
*
778 (format t
"~&FRAC-BFLOAT-EXPINTEGRAL-E called with:~%")
779 (format t
"~& : n = ~A~%" n
)
780 (format t
"~& : z = ~A~%" z
))
783 ((and (or (eq ($sign
($realpart z
)) '$pos
)
784 (eq ($sign
($realpart z
)) '$zero
))
785 (eq ($sign
(sub (cabs z
) bigfloatone
)) '$pos
))
786 ;; We expand in continued fractions.
787 (when *debug-expintegral
*
788 (format t
"We expand in continued fractions.~%"))
790 (c (div bigfloatone
(mul *expint-eps
* *expint-eps
*)))
791 (d (cdiv bigfloatone b
))
796 (a (mul -
1 n
) (cmul (- i
) (add n1 i
))))
797 ((> i
*expint-maxit
*)
799 (intl:gettext
"expintegral_e: continued fractions failed.")))
801 (setq b
(add b bigfloattwo
))
802 (setq d
(cdiv bigfloatone
(add (mul a d
) b
)))
803 (setq c
(add b
(cdiv a c
)))
807 (when (eq ($sign
(sub (cabs (sub e bigfloatone
)) *expint-eps
*))
809 (when *debug-expintegral
*
810 (setq *debug-expint-fracbfloatmaxit
*
811 (max *debug-expint-fracbfloatmaxit
* i
)))
812 (return (cmul h
(cpower bigfloat%e
(mul -
1 z
))))))))
814 ((or (and (numberp n
)
817 (= (nth-value 1 (truncate ($realpart n
))) 0))
820 (equal (sub (mul 2 ($fix n
)) (mul 2 n
))
822 ;; We have a Float or Bigfloat representation of positive integer.
823 ;; We call bfloat-expintegral-e.
824 (when *debug-expintegral
*
825 (format t
"frac-Bigfloat with integer ~A~%" n
))
826 (bfloat-expintegral-e ($fix
($realpart n
)) z
))
829 ;; At this point the parameter n is a real (not a float representation
830 ;; of an integer) or complex. We expand in a power series.
831 (when *debug-expintegral
*
832 (format t
"We expand in a power series.~%"))
833 (let* ((n1 (sub n bigfloatone
))
834 (n2 (sub bigfloatone n
))
835 (gm (take '(%gamma
) n2
))
836 (r (sub (cmul (cpower z n1
) gm
) (cdiv bigfloatone n2
)))
840 ((> i
*expint-maxit
*)
841 (merror (intl:gettext
"expintegral_e: series failed.")))
842 (setq f
(cmul (mul -
1 bigfloatone
) (cmul f
(cdiv z i
))))
843 (setq e
(cdiv (mul -
1 f
) (sub i n1
)))
845 (when (eq ($sign
(sub (cabs e
) (cmul (cabs r
) *expint-eps
*)))
847 (when *debug-expintegral
*
848 (setq *debug-expint-fracbfloatmaxit
*
849 (max *debug-expint-fracbfloatmaxit
* i
)))
852 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
854 ;;; Part 2: The implementation of the Exponential Integral E1
856 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
858 ;;; Exponential Integral E1 distributes over bags
860 (defprop %expintegral_e1
(mlist $matrix mequal
) distribute_over
)
862 ;;; Exponential Integral E1 has mirror symmetry,
863 ;;; but not on the real negative axis.
865 (defprop %expintegral_e1 conjugate-expintegral-e1 conjugate-function
)
867 (defun conjugate-expintegral-e1 (args)
868 (let ((z (first args
)))
869 (cond ((off-negative-real-axisp z
)
870 ;; Definitely not on the negative real axis for z. Mirror symmetry.
871 (take '(%expintegral_e1
) (take '($conjugate
) z
)))
873 ;; On the negative real axis or no information. Unsimplified.
874 (list '($conjugate simp
) (take '(%expintegral_e1
) z
))))))
876 ;;; Differentiation of Exponential Integral E1
878 (defprop %expintegral_e1
882 ((mexpt) $%e
((mtimes) -
1 x
))))
885 ;;; Integral of Exponential Integral E1
887 (defprop %expintegral_e1
889 ((mtimes) -
1 ((%expintegral_e
) 2 z
)))
892 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
894 ;;; We support a simplim%function. The function is looked up in simplimit and
895 ;;; handles specific values of the function.
897 (defprop %expintegral_e1 simplim%expintegral_e1 simplim%function
)
899 (defun simplim%expintegral_e1
(expr var val
)
900 ;; Look for the limit of the argument.
901 (let ((z (limit (cadr expr
) var val
'think
)))
903 ;; Handle an argument 0 at this place
907 ;; limit is inf from both sides
910 ;; All other cases are handled by the simplifier of the function.
911 (take '(%expintegral_e1
) z
)))))
913 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
915 ;;; Exponential Integral E1 is a simplifying function
916 (def-simplifier expintegral_e1
(arg)
918 ;; Check for special values
920 (alike1 arg
'((mtimes) -
1 $minf
)))
924 (intl:gettext
"expintegral_e1: expintegral_e1(~:M) is undefined.") arg
))
926 ;; Check for numerical evaluation
927 ((complex-float-numerical-eval-p arg
)
928 ;; For E1 we call En(z) with n=1 directly.
929 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
930 (complexify (expintegral-e 1 carg
))))
932 ((complex-bigfloat-numerical-eval-p arg
)
933 ;; For E1 we call En(z) with n=1 directly.
934 (let* (($ratprint nil
)
935 (carg (add ($bfloat
($realpart arg
))
936 (mul '$%i
($bfloat
($imagpart arg
)))))
937 (result (bfloat-expintegral-e 1 carg
)))
938 (add ($realpart result
)
939 (mul '$%i
($imagpart result
)))))
941 ;; Check argument simplifications and transformations
942 ((taylorize (mop form
) (second form
)))
945 (member $expintrep
*expintflag
* :test
#'eq
)
946 (not (eq $expintrep
'%expintegral_e1
)))
949 (take '(%gamma_incomplete
) 0 arg
))
951 (add (mul -
1 (take '(%expintegral_ei
) (mul -
1 arg
)))
953 (sub (take '(%log
) (mul -
1 arg
))
954 (take '(%log
) (mul -
1 (inv arg
)))))
955 (mul -
1 (take '(%log
) arg
))))
957 (add (mul -
1 (take '(%expintegral_li
) (power '$%e
(mul -
1 arg
))))
958 (mul -
1 (take '(%log
) arg
))
960 (sub (take '(%log
) (mul -
1 arg
))
961 (take '(%log
) (mul -
1 (inv arg
)))))))
963 (add (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i arg
)))
964 (mul -
1 (take '(%expintegral_ci
) (mul '$%i arg
)))
965 (take '(%log
) (mul '$%i arg
))
966 (mul -
1 (take '(%log
) arg
))))
968 (sub (take '(%expintegral_shi
) arg
)
969 (take '(%expintegral_chi
) arg
)))
976 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
978 ;;; Part 3: The implementation of the Exponential Integral Ei
980 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
982 ;;; Exponential Integral Ei distributes over bags
984 (defprop %expintegral_ei
(mlist $matrix mequal
) distribute_over
)
986 ;;; Exponential Integral Ei has mirror symmetry
988 (defprop %expintegral_ei t commutes-with-conjugate
)
990 ;;; Differentiation of Exponential Integral Ei
992 (defprop %expintegral_ei
994 ((mtimes) ((mexpt) x -
1) ((mexpt) $%e x
)))
997 ;;; Integral of Exponential Ei
999 (defprop %expintegral_ei
1002 ((mtimes) -
1 ((mexpt) $%e x
))
1003 ((mtimes) x
((%expintegral_ei
) x
))))
1006 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1008 ;;; We support a simplim%function. The function is looked up in simplimit and
1009 ;;; handles specific values of the function.
1011 (defprop %expintegral_ei simplim%expintegral_ei simplim%function
)
1013 (defun simplim%expintegral_ei
(expr var val
)
1014 ;; Look for the limit of the arguments.
1015 (let ((z (limit (cadr expr
) var val
'think
)))
1017 ;; Handle an argument 0 at this place
1023 ;; All other cases are handled by the simplifier of the function.
1024 (take '(%expintegral_ei
) z
)))))
1026 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1028 ;;; Exponential Integral Ei is a simplifying function
1029 (def-simplifier expintegral_ei
(arg)
1031 ;; Check special values
1034 (intl:gettext
"expintegral_ei: expintegral_ei(~:M) is undefined.")
1037 (alike1 arg
'((mtimes) -
1 $minf
)))
1039 ((or (eq arg
'$minf
)
1040 (alike1 arg
'((mtimes) -
1 $inf
)))
1042 ((or (alike1 arg
'((mtimes) $%i $inf
))
1043 (alike1 arg
'((mtimes) -
1 $%i $minf
)))
1045 ((or (alike1 arg
'((mtimes) $%i $minf
))
1046 (alike1 arg
'((mtimes) -
1 $%i $inf
)))
1047 (mul -
1 '$%i
'$%pi
))
1049 ;; Check numerical evaluation
1050 ((complex-float-numerical-eval-p arg
)
1051 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1052 (complexify (expintegral-ei carg
))))
1054 ((complex-bigfloat-numerical-eval-p arg
)
1055 (let* (($ratprint nil
)
1056 (carg (add ($bfloat
($realpart arg
))
1057 (mul '$%i
($bfloat
($imagpart arg
)))))
1058 (result (bfloat-expintegral-ei carg
)))
1059 (add ($realpart result
)
1060 (mul '$%i
($imagpart result
)))))
1062 ;; Check argument simplifications and transformations
1063 ((taylorize (mop form
) (second form
)))
1066 (member $expintrep
*expintflag
*)
1067 (not (eq $expintrep
'%expintegral_ei
)))
1070 (add (mul -
1 (take '(%gamma_incomplete
) 0 (mul -
1 arg
)))
1072 (sub (take '(%log
) arg
)
1073 (take '(%log
) (inv arg
))))
1074 (mul -
1 (take '(%log
) (mul -
1 arg
)))))
1076 (add (mul -
1 (take '(%expintegral_e1
) (mul -
1 arg
)))
1078 (sub (take '(%log
) arg
)
1079 (take '(%log
) (inv arg
))))
1080 (mul -
1 (take '(%log
) (mul -
1 arg
)))))
1082 (take '(%expintegral_li
) (power '$%e arg
)))
1084 (add (take '(%expintegral_ci
) (mul '$%i arg
))
1085 (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i arg
)))
1087 (sub (take '(%log
) (inv arg
))
1088 (take '(%log
) arg
)))
1089 (mul -
1 (take '(%log
) (mul '$%i arg
)))))
1091 (add (take '(%expintegral_chi
) arg
)
1092 (take '(%expintegral_shi
) arg
)
1094 (add (take '(%log
) (inv arg
))
1095 (take '(%log
) arg
)))))))
1097 ($hypergeometric_representation
1098 ;; See http://functions.wolfram.com/06.35.26.0001.01
1100 ;; expintegral_ei(z) = z*hypergeometric([1,1],[2,2],z)
1101 ;; + 1/2*(log(z) - log(1/z)) + %gamma
1103 ;; But note that Maxima expands log(1/z) to -log(z), but this is
1104 ;; not true when z is on the negative real axis. log(-1/2) =
1105 ;; -log(2) + %i*%pi, but log(-2) = log(2) + %i*%pi. Hence,
1106 ;; log(-1/2) is not -log(2).
1108 (ftake '%hypergeometric
1113 (sub (ftake '%log arg
)
1114 (ftake '%log
(div 1 arg
))))
1119 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1120 ;;; Numerical evaluation of the Exponential Integral Ei(z):
1122 ;;; We use the following representation (see functions.wolfram.com):
1124 ;;; Ei(z) = -E1(-z) + 0.5*(log(z)-log(1/z))-log(-z)
1126 ;;; z is a CL Complex number. Because we evaluate for Complex values we have to
1127 ;;; take into account the complete Complex phase factors.
1128 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1130 (defun expintegral-ei (z)
1131 (+ (- (expintegral-e 1 (- z
)))
1132 ;; Carefully compute 1/2*(log(z)-log(1/z))-log(-z), using the
1133 ;; branch cuts that we want, not the one that Lisp wants.
1134 ;; (Mostly an issue with Lisps that support signed zeroes.)
1137 ;; Positive imaginary part. Add phase %i*%pi.
1138 (complex 0 (float pi
)))
1140 ;; Negative imaginary part. Add phase -%i*%pi.
1141 (complex 0 (- (float pi
))))
1143 ;; Positive real value. Add phase -%i*pi.
1144 (complex 0 (- (float pi
))))
1145 ;; Negative real value. No phase factor.
1148 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1149 ;;; We have not modified the algorithm for Bigfloat numbers. It is only
1150 ;;; generalized for Bigfloats. The calculation of the complex phase factor
1151 ;;; can be simplified to conditions about the sign of the realpart and
1152 ;;; imagpart. We leave this for further work to optimize the speed of the
1154 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1156 (defun bfloat-expintegral-ei (z)
1157 (let ((mz (mul -
1 z
)))
1158 (add (cmul (mul -
1 bigfloatone
)
1159 (bfloat-expintegral-e 1 mz
))
1160 (sub (cmul (div bigfloatone
2)
1161 (sub (take '(%log
) z
)
1162 (take '(%log
) (cdiv bigfloatone z
))))
1163 (take '(%log
) mz
)))))
1165 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1167 ;;; Part 4: The implementation of the Logarithmic integral li(z)
1169 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1171 ;;; Exponential Integral Li distributes over bags
1173 (defprop %expintegral_li
(mlist $matrix mequal
) distribute_over
)
1175 ;;; Exponential Integral Li has mirror symmetry,
1176 ;;; but not on the real negative axis.
1178 (defprop %expintegral_li conjugate-expintegral-li conjugate-function
)
1180 (defun conjugate-expintegral-li (args)
1181 (let ((z (first args
)))
1182 (cond ((off-negative-real-axisp z
)
1183 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1184 (take '(%expintegral_li
) (take '($conjugate
) z
)))
1186 ;; On the negative real axis or no information. Unsimplified.
1187 (list '($conjugate simp
) (take '(%expintegral_li
) z
))))))
1189 ;;; Differentiation of Exponential Integral Li
1191 (defprop %expintegral_li
1193 ((mtimes) ((mexpt) ((%log
) x
) -
1)))
1196 ;;; Integral of Exponential Li
1198 (defprop %expintegral_li
1201 ((mtimes) x
((%expintegral_li
) x
))
1202 ((mtimes) -
1 ((%expintegral_ei
) ((mtimes) 2 ((%log
) x
))))))
1205 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1207 ;;; We support a simplim%function. The function is looked up in simplimit and
1208 ;;; handles specific values of the function.
1210 (defprop %expintegral_li simplim%expintegral_li simplim%function
)
1212 (defun simplim%expintegral_li
(expr var val
)
1213 ;; Look for the limit of the argument.
1214 (let ((z (limit (cadr expr
) var val
'think
)))
1216 ;; Handle an argument 1 at this place
1219 ;; All other cases are handled by the simplifier of the function.
1220 (take '(%expintegral_li
) z
)))))
1222 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1224 ;;; Exponential Integral Li is a simplifying function
1225 (def-simplifier expintegral_li
(arg)
1230 (intl:gettext
"expintegral_li: expintegral_li(~:M) is undefined.") arg
))
1232 (alike1 arg
'((mtimes) -
1 $minf
)))
1234 ((eq arg
'$infinity
) '$infinity
)
1236 ((complex-float-numerical-eval-p arg
)
1237 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1238 (complexify (expintegral-li carg
))))
1240 ((complex-bigfloat-numerical-eval-p arg
)
1241 (let* (($ratprint nil
)
1242 (carg (add ($bfloat
($realpart arg
))
1243 (mul '$%i
($bfloat
($imagpart arg
)))))
1244 (result (bfloat-expintegral-li carg
)))
1245 (add (mul '$%i
($imagpart result
))
1246 ($realpart result
))))
1248 ;; Check for argument simplifications and transformations
1249 ((taylorize (mop form
) (second form
)))
1252 (member $expintrep
*expintflag
*)
1253 (not (eq $expintrep
'%expintegral_li
)))
1254 (let ((logarg (take '(%log
) arg
)))
1257 (add (mul -
1 (take '(%gamma_incomplete
) 0 (mul -
1 logarg
)))
1259 (sub (take '(%log
) logarg
)
1260 (take '(%log
) (inv logarg
))))
1261 (mul -
1 (take '(%log
) (mul -
1 logarg
)))))
1263 (add (mul -
1 (take '(%expintegral_e1
) (mul -
1 logarg
)))
1265 (sub (take '(%log
) logarg
)
1266 (take '(%log
) (inv logarg
))))
1267 (mul -
1 (take '(%log
) (mul -
1 logarg
)))))
1269 (take '(%expintegral_ei
) logarg
))
1271 (add (take '(%expintegral_ci
) (mul '$%i logarg
))
1272 (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i logarg
)))
1274 (sub (take '(%log
) (inv logarg
))
1275 (take '(%log
) logarg
)))
1276 (mul -
1 (take '(%log
) (mul '$%i logarg
)))))
1278 (add (take '(%expintegral_chi
) logarg
)
1279 (take '(%expintegral_shi
) logarg
)
1281 (add (take '(%log
) (inv logarg
))
1282 (take '(%log
) logarg
))))))))
1283 ($hypergeometric_representation
1284 ;; See http://functions.wolfram.com/06.36.26.0001.01
1286 ;; expintegral_li(z) = log(z)*hypergeometric([1,1],[2,2],log(z))
1287 ;; + 1/2*(log(log(z)) - log(1/log(z))) + %gamma
1289 ;; But note that Maxima expands log(1/z) to -log(z), but this is
1290 ;; not true when z is on the negative real axis. log(-1/2) =
1291 ;; -log(2) + %i*%pi, but log(-2) = log(2) + %i*%pi. Hence,
1292 ;; log(-1/2) is not -log(2).
1293 (add (mul (ftake '%log arg
)
1294 (ftake '%hypergeometric
1299 (sub (ftake '%log
(ftake '%log arg
))
1300 (ftake '%log
(div 1 (ftake '%log arg
)))))
1305 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1306 ;;; Numerical evaluation of the Expintegral Li
1308 ;;; We use the representation:
1310 ;;; Li(z) = Ei(log(z))
1311 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1313 (defun expintegral-li (z)
1314 (expintegral-ei (log z
)))
1316 (defun bfloat-expintegral-li (z)
1317 (bfloat-expintegral-ei ($log z
)))
1319 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1321 ;;; Part 5: The implementation of the Exponential Integral Si
1323 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1325 ;;; Exponential Integral Si distributes over bags
1327 (defprop %expintegral_si
(mlist $matrix mequal
) distribute_over
)
1329 ;;; Exponential Integral Si has mirror symmetry
1331 (defprop %expintegral_si t commutes-with-conjugate
)
1333 ;;; Exponential Integral Si is a odd function
1335 (defprop %expintegral_si odd-function-reflect reflection-rule
)
1337 ;;; Differentiation of Exponential Integral Si
1339 (defprop %expintegral_si
1341 ((mtimes) ((%sin
) x
) ((mexpt) x -
1)))
1344 ;;; Integral of Exponential Si
1346 (defprop %expintegral_si
1350 ((mtimes) x
((%expintegral_si
) x
))))
1353 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1355 ;;; We support a simplim%function.
1357 (defprop %expintegral_si simplim%expintegral_si simplim%function
)
1359 (defun simplim%expintegral_si
(expr var val
)
1360 ;; Look for the limit of the argument.
1361 (let ((z (limit (cadr expr
) var val
'think
)))
1362 ;; All cases are handled by the simplifier of the function.
1363 (take '(%expintegral_si
) z
)))
1365 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1367 ;;; Exponential Integral Si is a simplifying function
1368 (def-simplifier expintegral_si
(arg)
1370 ;; Check for special values
1373 (alike1 arg
'((mtimes) -
1 $minf
)))
1375 ((or (eq arg
'$minf
)
1376 (alike1 arg
'((mtimes) -
1 $inf
)))
1377 (mul -
1 (div '$%pi
2)))
1379 ;; Check for numerical evaluation
1380 ((complex-float-numerical-eval-p arg
)
1381 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1382 (complexify (expintegral-si carg
))))
1384 ((complex-bigfloat-numerical-eval-p arg
)
1385 (let* (($ratprint nil
)
1386 (carg (add ($bfloat
($realpart arg
))
1387 (mul '$%i
($bfloat
($imagpart arg
)))))
1388 (result (bfloat-expintegral-si carg
)))
1389 (add (mul '$%i
($imagpart result
))
1390 ($realpart result
))))
1392 ;; Check for argument simplifications and transformations
1393 ((taylorize (mop form
) (second form
)))
1394 ((apply-reflection-simp (mop form
) arg $trigsign
))
1397 (member $expintrep
*expintflag
*)
1398 (not (eq $expintrep
'$expintegral_trig
)))
1402 (add (take '(%gamma_incomplete
) 0 (mul -
1 '$%i arg
))
1403 (mul -
1 (take '(%gamma_incomplete
) 0 (mul '$%i arg
)))
1404 (take '(%log
) (mul -
1 '$%i arg
))
1405 (mul -
1 (take '(%log
) (mul '$%i arg
))))))
1408 (add (take '(%expintegral_e1
) (mul -
1 '$%i arg
))
1409 (mul -
1 (take '(%expintegral_e1
) (mul '$%i arg
)))
1410 (take '(%log
) (mul -
1 '$%i arg
))
1411 (mul -
1 (take '(%log
) (mul '$%i arg
))))))
1415 (sub (take '(%expintegral_ei
) (mul -
1 '$%i arg
))
1416 (take '(%expintegral_ei
) (mul '$%i arg
))))
1417 (take '(%log
) (div '$%i arg
))
1418 (mul -
1 (take '(%log
) (mul -
1 (div '$%i arg
))))
1419 (mul -
1 (take '(%log
) (mul -
1 '$%i arg
)))
1420 (take '(%log
) (mul '$%i arg
)))))
1422 (mul (inv (mul 2 '$%i
))
1423 (add (take '(%expintegral_li
) (power '$%e
(mul '$%i arg
)))
1425 (take '(%expintegral_li
)
1426 (power '$%e
(mul -
1 '$%e arg
))))
1428 (take '(%signum
) ($realpart arg
))))))
1430 (mul -
1 '$%i
(take '(%expintegral_shi
) (mul '$%i arg
))))))
1432 ($hypergeometric_representation
1433 ;; See http://functions.wolfram.com/06.37.26.0001.01
1435 ;; expintegral_si(z) = z*hypergeometric([1/2],[3/2,3/2],-z^2/4)
1438 (ftake '%hypergeometric
1440 (make-mlist 3//2 3//2)
1446 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1447 ;;; Numerical evaluation of the Exponential Integral Si
1449 ;;; We use the representation:
1451 ;;; Si(z) = %i/2 * (E1(-%i*z) - E1(*%i*z) + log(%i*z) - log(-%i*z))
1453 ;;; For the Sin, Cos, Sinh and Cosh Exponential Integrals we have to call the
1454 ;;; numerical evaluation twice. In principle we could use a direct expansion
1455 ;;; in a power series or continued fractions to optimize the speed of the code.
1456 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1458 (defun expintegral-si (z)
1459 (let ((z (coerce z
'(complex flonum
))))
1461 (+ (expintegral-e 1 (* (complex 0 -
1) z
))
1462 (- (expintegral-e 1 (* (complex 0 1) z
)))
1463 (log (* (complex 0 -
1) z
))
1464 (- (log (* (complex 0 1) z
)))))))
1466 (defun bfloat-expintegral-si (z)
1467 (let ((z*%i
(cmul '$%i z
))
1468 (mz*%i
(cmul (mul -
1 '$%i
) z
)))
1472 (bfloat-expintegral-e 1 mz
*%i
)
1473 (mul -
1 (bfloat-expintegral-e 1 z
*%i
))
1475 (mul -
1 ($log z
*%i
))))))
1477 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1479 ;;; Part 6: The implementation of the Exponential Integral Shi
1481 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1483 ;;; Exponential Integral Shi distributes over bags
1485 (defprop %expintegral_shi
(mlist $matrix mequal
) distribute_over
)
1487 ;;; Exponential Integral Shi has mirror symmetry
1489 (defprop %expintegral_si t commutes-with-conjugate
)
1491 ;;; Exponential Integral Shi is a odd function
1493 (defprop %expintegral_si odd-function-reflect reflection-rule
)
1495 ;;; Differentiation of Exponential Integral Shi
1497 (defprop %expintegral_shi
1499 ((mtimes) ((%sinh
) x
) ((mexpt) x -
1)))
1502 ;;; Integral of Exponential Shi
1504 (defprop %expintegral_shi
1507 ((mtimes) -
1 ((%cosh
) x
))
1508 ((mtimes) x
((%expintegral_shi
) x
))))
1511 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1513 ;;; We support a simplim%function. The function is looked up in simplimit and
1514 ;;; handles specific values of the function.
1516 (defprop %expintegral_shi simplim%expintegral_shi simplim%function
)
1518 (defun simplim%expintegral_shi
(expr var val
)
1519 ;; Look for the limit of the argument.
1520 (let ((z (limit (cadr expr
) var val
'think
)))
1522 ;; Handle infinities at this place
1528 ;; All other cases are handled by the simplifier of the function.
1529 (take '(%expintegral_shi
) z
)))))
1531 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1533 ;;; Exponential Integral Shi is a simplifying function
1534 (def-simplifier expintegral_shi
(arg)
1536 ;; Check for special values
1538 ((or (alike1 arg
'((mtimes) $%i $inf
))
1539 (alike1 arg
'((mtimes) -
1 $%i $minf
)))
1540 (div (mul '$%i
'$%pi
) 2))
1541 ((or (alike1 arg
'((mtimes) $%i $minf
))
1542 (alike1 arg
'((mtimes) -
1 $%i $inf
)))
1543 (div (mul -
1 '$%i
'$%pi
) 2))
1545 ;; Check for numrical evaluation
1546 ((float-numerical-eval-p arg
)
1547 (realpart (expintegral-shi arg
)))
1549 ((complex-float-numerical-eval-p arg
)
1550 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1551 (complexify (expintegral-shi carg
))))
1553 ((complex-bigfloat-numerical-eval-p arg
)
1554 (let* (($ratprint nil
)
1555 (carg (add ($bfloat
($realpart arg
))
1556 (mul '$%i
($bfloat
($imagpart arg
)))))
1557 (result (bfloat-expintegral-shi carg
)))
1558 (add (mul '$%i
($imagpart result
))
1559 ($realpart result
))))
1561 ;; Check for argument simplifications and transformations
1562 ((taylorize (mop form
) (second form
)))
1563 ((apply-reflection-simp (mop form
) arg $trigsign
))
1566 (member $expintrep
*expintflag
*)
1567 (not (eq $expintrep
'$expintegral_hyp
)))
1571 (add (take '(%gamma_incomplete
) 0 arg
)
1572 (mul -
1 (take '(%gamma_incomplete
) 0 (mul -
1 arg
)))
1573 (mul -
1 (take '(%log
) (mul -
1 arg
)))
1574 (take '(%log
) arg
))))
1577 (add (take '(%expintegral_e1
) arg
)
1578 (mul -
1 (take '(%expintegral_e1
) (mul -
1 arg
)))
1579 (mul -
1 (take '(%log
) (mul -
1 arg
)))
1580 (take '(%log
) arg
))))
1584 (sub (take '(%expintegral_ei
) arg
)
1585 (take '(%expintegral_ei
) (mul -
1 arg
))))
1586 (take '(%log
) (inv arg
))
1587 (mul -
1 (take '(%log
) (mul -
1 (inv arg
))))
1588 (take '(%log
) (mul -
1 arg
))
1589 (mul -
1 (take '(%log
) arg
)))))
1592 (sub (take '(%expintegral_li
) (power '$%e arg
))
1593 (take '(%expintegral_li
) (power '$%e
(mul -
1 arg
)))))
1594 (mul (div (mul '$%i
'$%pi
) -
2)
1595 (take '(%signum
) ($imagpart arg
)))))
1597 (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i arg
))))))
1599 ($hypergeometric_representation
1600 ;; See http://functions.wolfram.com/06.39.26.0001.01
1602 ;; expintegral_shi(z) = z*hypergeometric([1/2],[3/2,3/2],z^2/4)
1605 (ftake '%hypergeometric
1607 (make-mlist 3//2 3//2)
1613 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1614 ;;; Numerical evaluation of the Exponential Integral Shi
1616 ;;; We use the representation:
1618 ;;; Shi(z) = 1/2 * (E1(z) - E1(-z) - log(-z) + log(z))
1620 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1622 (defun expintegral-shi (z)
1627 (- (expintegral-e 1 (- z
)))
1631 (defun bfloat-expintegral-shi (z)
1632 (let ((mz (mul -
1 z
)))
1636 (bfloat-expintegral-e 1 z
)
1637 (mul -
1 (bfloat-expintegral-e 1 mz
))
1641 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1643 ;;; Part 7: The implementation of the Exponential Integral Ci
1645 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1647 ;;; Exponential Integral Ci distributes over bags
1649 (defprop %expintegral_ci
(mlist $matrix mequal
) distribute_over
)
1651 ;;; Exponential Integral Ci has mirror symmetry,
1652 ;;; but not on the real negative axis.
1654 (defprop %expintegral_ci conjugate-expintegral-ci conjugate-function
)
1656 (defun conjugate-expintegral-ci (args)
1657 (let ((z (first args
)))
1658 (cond ((off-negative-real-axisp z
)
1659 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1660 (take '(%expintegral_ci
) (take '($conjugate
) z
)))
1662 ;; On the negative real axis or no information. Unsimplified.
1663 (list '($conjugate simp
) (take '(%expintegral_ci
) z
))))))
1665 ;;; Differentiation of Exponential Integral Ci
1667 (defprop %expintegral_ci
1669 ((mtimes) ((%cos
) x
) ((mexpt) x -
1)))
1672 ;;; Integral of Exponential Ci
1674 (defprop %expintegral_ci
1677 ((mtimes) x
((%expintegral_ci
) x
))
1678 ((mtimes) -
1 ((%sin
) x
))))
1681 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1683 ;;; We support a simplim%function. The function is looked up in simplimit and
1684 ;;; handles specific values of the function.
1686 (defprop %expintegral_ci simplim%expintegral_ci simplim%function
)
1688 (defun simplim%expintegral_ci
(expr var val
)
1689 ;; Look for the limit of the argument.
1690 (let ((z (limit (cadr expr
) var val
'think
)))
1692 ;; Handle an argument 0 at this place
1698 ;; All other cases are handled by the simplifier of the function.
1699 (take '(%expintegral_ci
) z
)))))
1701 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1703 ;;; Exponential Integral Ci is a simplifying function
1704 (def-simplifier expintegral_ci
(arg)
1706 ;; Check for special values
1709 (intl:gettext
"expintegral_ci: expintegral_ci(~:M) is undefined.") arg
))
1711 (alike1 arg
'((mtimes) -
1 $minf
)))
1713 ((or (eq arg
'$minf
)
1714 (alike1 arg
'((mtimes) -
1 $inf
)))
1717 ;; Check for numerical evaluation
1718 ((complex-float-numerical-eval-p arg
)
1719 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1720 (complexify (expintegral-ci carg
))))
1722 ((complex-bigfloat-numerical-eval-p arg
)
1723 (let* (($ratprint nil
)
1724 (carg (add ($bfloat
($realpart arg
))
1725 (mul '$%i
($bfloat
($imagpart arg
)))))
1726 (result (bfloat-expintegral-ci carg
)))
1727 (add (mul '$%i
($imagpart result
))
1728 ($realpart result
))))
1730 ;; Check for argument simplifications and transformations
1731 ((taylorize (mop form
) (second form
)))
1734 (member $expintrep
*expintflag
*)
1735 (not (eq $expintrep
'$expintegral_trig
)))
1738 (sub (take '(%log
) arg
)
1740 (add (take '(%gamma_incomplete
) 0 (mul -
1 '$%i arg
))
1741 (take '(%gamma_incomplete
) 0 (mul '$%i arg
))
1742 (take '(%log
) (mul -
1 '$%i arg
))
1743 (take '(%log
) (mul '$%i arg
))))))
1746 (add (take '(%expintegral_e1
) (mul -
1 '$%i arg
))
1747 (take '(%expintegral_e1
) (mul '$%i arg
)))
1748 (take '(%log
) (mul -
1 '$%i arg
))
1749 (take '(%log
) (mul '$%i arg
)))
1750 (take '(%log
) arg
)))
1754 (add (take '(%expintegral_ei
) (mul -
1 '$%i arg
))
1755 (take '(%expintegral_ei
) (mul '$%i arg
))))
1756 (take '(%log
) (div '$%i arg
))
1757 (take '(%log
) (mul -
1 '$%i
(inv arg
)))
1758 (mul -
1 (take '(%log
) (mul -
1 '$%i arg
)))
1759 (mul -
1 (take '(%log
) (mul '$%i arg
)))))
1760 (take '(%log
) arg
)))
1763 (add (take '(%expintegral_li
)
1764 (power '$%e
(mul -
1 '$%i arg
)))
1765 (take '(%expintegral_li
)
1766 (power '$%e
(mul '$%i arg
)))))
1767 (mul (div (mul '$%i
'$%pi
) 2)
1768 (take '(%signum
) ($imagpart arg
)))
1769 (sub 1 (take '(%signum
) ($realpart arg
)))))
1771 (add (take '(%expintegral_chi
) (mul '$%i arg
))
1772 (mul -
1 (take '(%log
) (mul '$%i arg
)))
1773 (take '(%log
) arg
)))))
1775 ($hypergeometric_representation
1776 ;; See http://functions.wolfram.com/06.38.26.0001.01
1778 ;; expintegral_ci(z) = -z^2/4*hypergeometric([1,1],[2,2,3/2],-z^2/4)
1779 ;; + log(z) + %gamma
1782 (mul (div (mul arg arg
) -
4)
1783 (ftake '%hypergeometric
1785 (make-mlist 2 2 3//2)
1793 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1794 ;;; Numerical evaluation of the Exponential Integral Ci
1796 ;;; We use the representation:
1798 ;;; Ci(z) = -1/2 * (E1(-%i*z) + E1(%i*z) + log(-%i*z) + log(%i*z)) + log(z)
1800 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1802 (defun expintegral-ci (z)
1803 (let ((z (coerce z
'(complex flonum
))))
1805 (+ (expintegral-e 1 (* (complex 0 -
1) z
))
1806 (expintegral-e 1 (* (complex 0 1) z
))
1807 (log (* (complex 0 -
1) z
))
1808 (log (* (complex 0 1) z
))))
1811 (defun bfloat-expintegral-ci (z)
1812 (let ((z*%i
(cmul '$%i z
))
1813 (mz*%i
(cmul (mul -
1 '$%i
) z
)))
1818 (bfloat-expintegral-e 1 mz
*%i
)
1819 (bfloat-expintegral-e 1 z
*%i
)
1824 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1826 ;;; Part 8: The implementation of the Exponential Integral Chi
1828 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1830 ;;; Exponential Integral Chi distributes over bags
1832 (defprop %expintegral_chi
(mlist $matrix mequal
) distribute_over
)
1834 ;;; Exponential Integral Chi has mirror symmetry,
1835 ;;; but not on the real negative axis.
1837 (defprop %expintegral_chi conjugate-expintegral-chi conjugate-function
)
1839 (defun conjugate-expintegral-chi (args)
1840 (let ((z (first args
)))
1841 (cond ((off-negative-real-axisp z
)
1842 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1843 (take '(%expintegral_chi
) (take '($conjugate
) z
)))
1845 ;; On the negative real axis or no information. Unsimplified.
1846 (list '($conjugate simp
) (take '(%expintegral_chi
) z
))))))
1848 ;;; Differentiation of Exponential Integral Chi
1850 (defprop %expintegral_chi
1852 ((mtimes) ((%cosh
) x
) ((mexpt) x -
1)))
1855 ;;; Integral of Exponential Chi
1857 (defprop %expintegral_chi
1860 ((mtimes) x
((%expintegral_chi
) x
))
1861 ((mtimes) -
1 ((%sinh
) x
))))
1864 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1866 ;;; We support a simplim%function. The function is looked up in simplimit and
1867 ;;; handles specific values of the function.
1869 (defprop %expintegral_chi simplim%expintegral_chi simplim%function
)
1871 (defun simplim%expintegral_chi
(expr var val
)
1872 ;; Look for the limit of the argument.
1873 (let ((z (limit (cadr expr
) var val
'think
)))
1875 ;; Handle an argument 0 at this place
1884 ;; All other cases are handled by the simplifier of the function.
1885 (take '(%expintegral_chi
) z
)))))
1887 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1889 ;;; Exponential Integral Chi is a simplifying function
1890 (def-simplifier expintegral_chi
(arg)
1892 ;; Check for special values
1894 ;; First check for zero argument. Throw Maxima error.
1896 (intl:gettext
"expintegral_chi: expintegral_chi(~:M) is undefined.")
1898 ((or (alike1 arg
'((mtimes) $%i $inf
))
1899 (alike1 arg
'((mtimes) -
1 $%i $minf
)))
1900 (div (mul '$%pi
'$%i
) 2))
1901 ((or (alike1 arg
'((mtimes) $%i $minf
))
1902 (alike1 arg
'((mtimes) -
1 $%i $inf
)))
1903 (div (mul -
1 '$%pi
'$%i
) 2))
1905 ;; Check for numerical evaluation
1906 ((complex-float-numerical-eval-p arg
)
1907 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1908 (complexify (expintegral-chi carg
))))
1910 ((complex-bigfloat-numerical-eval-p arg
)
1911 (let* (($ratprint nil
)
1912 (carg (add ($bfloat
($realpart arg
))
1913 (mul '$%i
($bfloat
($imagpart arg
)))))
1914 (result (bfloat-expintegral-chi carg
)))
1915 (add (mul '$%i
($imagpart result
))
1916 ($realpart result
))))
1918 ;; Check for argument simplifications and transformations
1919 ((taylorize (mop form
) (second form
)))
1922 (member $expintrep
*expintflag
*)
1923 (not (eq $expintrep
'$expintegral_hyp
)))
1927 (add (take '(%gamma_incomplete
) 0 (mul -
1 arg
))
1928 (take '(%gamma_incomplete
) 0 arg
)
1929 (take '(%log
) (mul -
1 arg
))
1930 (mul -
1 (take '(%log
) arg
)))))
1933 (add (take '(%expintegral_e1
) (mul -
1 arg
))
1934 (take '(%expintegral_e1
) arg
)
1935 (take '(%log
) (mul -
1 arg
))
1936 (mul -
1 (take '(%log
) arg
)))))
1940 (add (take '(%expintegral_ei
) (mul -
1 arg
))
1941 (take '(%expintegral_ei
) arg
)))
1942 (take '(%log
) (inv arg
))
1943 (take '(%log
) (mul -
1 (inv arg
)))
1944 (mul -
1 (take '(%log
) (mul -
1 arg
)))
1945 (mul 3 (take '(%log
) arg
)))))
1948 (add (take '(%expintegral_li
) (power '$%e
(mul -
1 arg
)))
1949 (take '(%expintegral_li
) (power '$%e arg
))))
1950 (mul (div (mul '$%i
'$%pi
) 2)
1951 (take '(%signum
) ($imagpart arg
)))
1953 (add (take '(%log
) (inv arg
))
1954 (take '(%log
) arg
)))))
1956 (add (take '(%expintegral_ci
) (mul '$%i arg
))
1958 (mul -
1 (take '(%log
) (mul '$%i arg
)))))))
1960 ($hypergeometric_representation
1961 ;; See http://functions.wolfram.com/06.40.26.0001.01
1963 ;; expintegral_chi(z) = z^2/4*hypergeometric([1,1],[2,2,3/2],z^2/4)
1964 ;; + log(z) + %gamma
1967 (mul (div (mul arg arg
) 4)
1968 (ftake '%hypergeometric
1970 (make-mlist 2 2 3//2)
1978 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1979 ;;; Numerical evaluation of the Exponential Integral Ci
1981 ;;; We use the representation:
1983 ;;; Chi(z) = -1/2 * (E1(-z) + E1(z) + log(-z) - log(z))
1985 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1987 (defun expintegral-chi (z)
1992 (expintegral-e 1 (- z
))
1996 (defun bfloat-expintegral-chi (z)
1997 (let ((mz (mul -
1 z
)))
2001 (bfloat-expintegral-e 1 z
)
2002 (bfloat-expintegral-e 1 mz
)
2004 (mul -
1 ($log z
))))))
2006 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2007 ;; Moved from bessel.lisp 2008-12-11. Consider deleting it.
2009 ;; Exponential integral E1(x). The Cauchy principal value is used for
2011 (defmfun $expint
(x)
2013 (values (slatec:de1
(float x
))))
2015 (list '($expint simp
) x
))))