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., 675 Mass Ave, Cambridge, MA 02139, 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 (defmfun $expintegral_e
(v z
)
130 (simplify (list '(%expintegral_e
) v z
)))
132 ;;; Set properties to give full support to the parser and display
134 (defprop $expintegral_e %expintegral_e alias
)
135 (defprop $expintegral_e %expintegral_e verb
)
137 (defprop %expintegral_e $expintegral_e reversealias
)
138 (defprop %expintegral_e $expintegral_e noun
)
140 ;;; Exponential Integral E is a simplifying function
142 (defprop %expintegral_e simp-expintegral-e operators
)
144 ;;; Exponential Integral E distributes over bags
146 (defprop %expintegral_e
(mlist $matrix mequal
) distribute_over
)
148 ;;; Exponential Integral E has mirror symmetry,
149 ;;; but not on the real negative axis.
151 (defprop %expintegral_e conjugate-expintegral-e conjugate-function
)
153 (defun conjugate-expintegral-e (args)
154 (let ((n (first args
))
156 (cond ((off-negative-real-axisp z
)
157 ;; Definitely not on the negative real axis for z. Mirror symmetry.
158 (take '(%expintegral_e
)
159 (take '($conjugate
) n
)
160 (take '($conjugate
) z
)))
162 ;; On the negative real axis or no information. Unsimplified.
163 (list '($conjugate simp
)
164 (take '(%expintegral_e
) n z
))))))
166 ;;; Differentiation of Exponential Integral E
168 (defprop %expintegral_e
170 ;; The derivative wrt the parameter n is expressed in terms of the
171 ;; Regularized Hypergeometric function 2F2 (see functions.wolfram.com)
174 (($hypergeometric_regularized
)
176 ((mplus) 1 ((mtimes) -
1 n
))
177 ((mplus) 1 ((mtimes) -
1 n
)))
179 ((mplus) 2 ((mtimes) -
1 n
))
180 ((mplus) 2 ((mtimes) -
1 n
)))
183 ((%gamma
) ((mplus) 1 ((mtimes) -
1 n
))) 2))
185 ((%gamma
) ((mplus) 1 ((mtimes) -
1 n
)))
186 ((mexpt) z
((mplus) -
1 n
))
191 ((mplus) 1 ((mtimes) -
1 n
))))
194 ;; The derivative wrt the argument of the function
195 ((mtimes) -
1 ((%expintegral_e
) ((mplus) -
1 n
) z
)))
198 ;;; Integral of Exponential Integral E
200 (defprop %expintegral_e
203 ((mtimes) -
1 ((%expintegral_e
) ((mplus) 1 n
) z
)))
206 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
208 ;;; We support a simplim%function. The function is looked up in simplimit and
209 ;;; handles specific values of the function.
211 (defprop %expintegral_e simplim%expintegral_e simplim%function
)
213 (defun simplim%expintegral_e
(expr var val
)
214 ;; Look for the limit of the arguments.
215 (let ((a (limit (cadr expr
) var val
'think
))
216 (z (limit (caddr expr
) var val
'think
)))
217 (cond ((and (onep1 a
)
221 ;; Special case order a=1
224 ((member ($sign
(add ($realpart a
) -
1)) '($neg $nz $zero
))
225 ; realpart of order < 1
226 (cond ((eq z
'$zeroa
)
227 ;; from above, always inf
230 ;; this can be further improved to give a directed infinity
233 ;; no direction, return infinity
236 ($expintegral_e a z
))))
238 ;; All other cases are handled by the simplifier of the function.
239 ($expintegral_e a z
)))))
241 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
243 (defun simp-expintegral-e (expr ignored z
)
244 (declare (ignore ignored
))
246 (let ((order (simpcheck (cadr expr
) z
))
247 (arg (simpcheck (caddr expr
) z
))
250 ;; Check for special values
252 (alike1 arg
'((mtimes) -
1 $minf
)))
253 ;; arg is inf or -minf, return zero
257 (let ((sgn ($sign
(add ($realpart order
) -
1))))
260 ;; we handle the special case E[v](0) = 1/(v-1), for realpart(v)>1
261 (inv (add order -
1)))
262 ((member sgn
'($neg $nz $zero
))
265 "expintegral_e: expintegral_e(~:M,~:M) is undefined.")
267 (t (eqtest (list '(%expintegral_e
) order arg
) expr
)))))
269 ((or (and (symbolp order
) (member order infinities
))
270 (and (symbolp arg
) (member arg infinities
)))
271 ;; order or arg is one of the infinities, we return a noun form,
272 ;; but we have already handled the special value inf for arg.
273 (eqtest (list '(%expintegral_e
) order arg
) expr
))
275 ((and (numberp order
) (integerp order
))
276 ;; The parameter of the Exponential integral is an integer. For this
277 ;; case we can do further simplifications or numerical evaluation.
280 ;; Special case E[0](z) = %e^(-z)/z, z<>0
281 ;; The case z=0 is already handled.
282 (div (power '$%e
(mul -
1 arg
)) arg
))
285 ;; Special case E[-1](0) = ((z+1)*%e^(-z))/z^2, z<>0
286 ;; The case z=0 is already handled.
287 (div (mul (power '$%e
(mul -
1 arg
)) (add arg
1)) (mul arg arg
)))
290 ;; We expand in a series, z<>0
292 (factorial (- order
))
293 (power arg
(+ order -
1))
294 (power '$%e
(mul -
1 arg
))
295 (let ((index (gensumindex)))
297 (div (power arg index
)
298 (take '(mfactorial) index
))
299 index
0 (- order
) t
))))
302 (complex-float-numerical-eval-p arg
))
303 ;; Numerical evaluation for double float real or complex arg
304 ;; order is an integer > 0 and arg <> 0 for order < 2
305 (let ((carg (complex ($float
($realpart arg
))
306 ($float
($imagpart arg
)))))
307 (complexify (expintegral-e order carg
))))
310 (complex-bigfloat-numerical-eval-p arg
))
311 ;; Numerical evaluation for Bigfloat real or complex arg.
312 (let* (($ratprint nil
)
313 (carg (add ($bfloat
($realpart arg
))
314 (mul '$%i
($bfloat
($imagpart arg
)))))
315 (result (bfloat-expintegral-e order carg
)))
316 (add ($realpart result
) (mul '$%i
($imagpart result
)))))
318 ((and $expintexpand
(> order
0))
319 ;; We only expand in terms of the Exponential Integral Ei
320 ;; if the expand flag is set.
322 (power (mul -
1 arg
) (- order
1))
323 (inv (factorial (- order
1)))
324 (add (take '(%expintegral_ei
) (mul -
1 arg
))
326 (sub (take '(%log
) (mul -
1 (inv arg
)))
327 (take '(%log
) (mul -
1 arg
))))
329 (mul (power '$%e
(mul -
1 arg
))
330 (let ((index (gensumindex)))
332 (div (power arg
(add index -
1))
333 (take '($pochhammer
) (- 1 order
) index
))
334 index
1 (- order
1) t
)))))
336 ((eq $expintrep
'%gamma_incomplete
)
337 ;; We transform to the Incomplete Gamma function.
338 (mul (power arg
(- order
1))
339 (take '(%gamma_incomplete
) (- 1 order
) arg
)))
342 (eqtest (list '(%expintegral_e
) order arg
) expr
))))
344 ((complex-float-numerical-eval-p order arg
)
346 ((and (setq z
(integer-representation-p order
))
348 ;; We have a pure real positive order and the realpart is a float
349 ;; representation of an integer value.
350 ;; We call the routine for an integer order.
351 (let ((carg (complex ($float
($realpart arg
))
352 ($float
($imagpart arg
)))))
353 (complexify (expintegral-e z carg
))))
355 ;; The general case, order and arg are complex or real.
356 (let ((corder (complex ($float
($realpart order
))
357 ($float
($imagpart order
))))
358 (carg (complex ($float
($realpart arg
))
359 ($float
($imagpart arg
)))))
360 (complexify (frac-expintegral-e corder carg
))))))
362 ((complex-bigfloat-numerical-eval-p order arg
)
364 ((and (setq z
(integer-representation-p order
))
366 ;; We have a real positive order and the realpart is a Float or
367 ;; Bigfloat representation of an integer value.
368 ;; We call the routine for an integer order.
369 (let* (($ratprint nil
)
370 (carg (add ($bfloat
($realpart arg
))
371 (mul '$%i
($bfloat
($imagpart arg
)))))
372 (result (bfloat-expintegral-e z carg
)))
373 (add ($realpart result
)
374 (mul '$%i
($imagpart result
)))))
376 ;; the general case, order and arg are bigfloat or complex bigfloat
377 (let* (($ratprint nil
)
378 (corder (add ($bfloat
($realpart order
))
379 (mul '$%i
($bfloat
($imagpart order
)))))
380 (carg (add ($bfloat
($realpart arg
))
381 (mul '$%i
($bfloat
($imagpart arg
)))))
382 (result (frac-bfloat-expintegral-e corder carg
)))
383 (add ($realpart result
)
384 (mul '$%i
($imagpart result
)))))))
387 (setq ratorder
(max-numeric-ratio-p order
2)))
388 ;; We have a half integral order and $expintexpand is not NIL.
389 ;; We expand in a series in terms of the Erfc or Erf function.
390 (let ((func (cond ((eq $expintexpand
'%erf
)
391 (sub 1 ($erf
(power arg
'((rat simp
) 1 2)))))
393 ($erfc
(power arg
'((rat simp
) 1 2)))))))
396 (mul (power '$%pi
'((rat simp
) 1 2))
397 (power arg
'((rat simp
) -
1 2))
402 (power '$%pi
'((rat simp
) 1 2))
403 (inv (mul 2 (power arg
'((rat simp
) 3 2))))
405 (div (power '$%e
(mul -
1 arg
)) arg
)))
407 (let ((n (- ratorder
1/2)))
409 (power arg
(sub n
'((rat simp
) 1 2)))
411 (mul func
(take '(%gamma
) (sub '((rat simp
) 1 2) n
)))
413 (power '$%e
(mul -
1 arg
))
414 (let ((index (gensumindex)))
417 (power arg
(add index
'((rat simp
) 1 2)))
419 (sub '((rat simp
) 1 2) n
)
421 index
0 (mul -
1 (add n
1)) t
)))
423 (power '$%e
(mul -
1 arg
))
424 (let ((index (gensumindex)))
427 (power arg
(add index
'((rat simp
) 1 2)))
429 (sub '((rat simp
) 1 2) n
)
431 index
(- n
) -
1 t
))))))))))
433 ((eq $expintrep
'%gamma_incomplete
)
434 ;; We transform to the Incomplete Gamma function.
435 (mul (power arg
(sub order
1))
436 (take '(%gamma_incomplete
) (sub 1 order
) arg
)))
439 (eqtest (list '(%expintegral_e
) order arg
) expr
)))))
441 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
442 ;;; Numerical evaluation of the Exponential Integral En(z)
444 ;;; The following numerical routines are implemented:
446 ;;; expintegral-e - n positive integer, z real or complex
447 ;;; frac-expintegral-e - n,z real or complex; n not a positive integer
448 ;;; bfloat-expintegral-e - n positive integer,
449 ;;; z Bigfloat or Complex Bigfloat
450 ;;; frac-bfloat-expintegral-e - n Bigfloat, z Bigfloat or Complex Bigfloat
452 ;;; The algorithm are implemented for full support of Flonum and Bigfloat real
453 ;;; or Complex parameter and argument of the Exponential Integral.
454 ;;; Because we have no support for Complex Bigfloat arguments of the Gamma
455 ;;; function the evaluation for a Complex Bigfloat parameter don't give
456 ;;; the desiered accuracy.
458 ;;; The flonum versions return a CL complex number. The Bigfloat versions
459 ;;; a Maxima Complex Bigfloat number. It is assumed that the calling routine
460 ;;; check the values. We don't handle any special case. This has to be done by
461 ;;; the calling routine.
463 ;;; The evaluation uses an expansion in continued fractions for arguments with
464 ;;; realpart(z) > 0 and abs(z)> 1.0 (A&S 5.1.22). This expansion works for
465 ;;; every Real or Complex numbers including Bigfloat numbers for the parameter n
466 ;;; and the argument z:
469 ;;; En(z) = e^(-z) * ( --- --- --- --- --- ... )
472 ;;; The continued fraction is evaluated by the modified Lentz's method
473 ;;; for the more rapidly converging even form.
475 ;;; For the parameter n an positive integer we do an expansion in a power series
479 ;;; (-z)^(n-1) \ (-z)^m
480 ;;; En(z) = --------- * (-log(z)+psi(n)) * > ---------- ; n an integer
481 ;;; (n-1)! / (m-n+1)*m!
485 ;;; For an parameter n not an integer we expand in the following series
486 ;;; (functions.wolfram.com ):
490 ;;; Ev(z) = gamma(1-v) * z^(v-1) * > ------------- ; n not an integer
495 ;;; The evaluation stops if an accuracy better than *expint-eps* is achieved.
496 ;;; If the expansion don't converge within *expint-maxit* steps a Maxima
499 ;;; The algorithm is based on technics desribed in Numerical Recipes, 2nd Ed.
500 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
502 ;;; Constants to terminate the numerical evaluation
504 ;;; The accuracy *expint-eps* is fixed to 1.0e-15 for double float calculations.
505 ;;; The variable is declared global, so we can later give the Maxima User access
506 ;;; to the variable. The routine for Bigfloat numerical evaluation change this
507 ;;; value to the desired precision of the global $fpprec.
508 ;;; The maximum number of iterations is arbitrary set to 1000. For Bigfloat
509 ;;; evaluation this number is for very Big numbers too small.
511 ;;; The maximum iterations counted for the test file rtest-expintegral.mac are
512 ;;; 101 for Complex Flonum and 1672 for Complex Bigfloat evaluation.
514 (defvar *expint-eps
* 1.0e-15)
515 (defvar *expint-maxit
* 1000)
517 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
519 (defun expintegral-e (n z
)
520 (declare (type integer n
))
521 (let ((*expint-eps
* *expint-eps
*)
522 (*expint-maxit
* *expint-maxit
*)
523 ;; Add (complex) 0 to get rid of any signed zeroes, and make z
524 ;; be a complex number.
525 (z (+ (coerce 0 '(complex flonum
)) z
)))
526 (declare (type (complex flonum
) z
))
528 (when *debug-expintegral
*
529 (format t
"~&EXPINTEGRAL-E called with:~%")
530 (format t
"~& : n = ~A~%" n
)
531 (format t
"~& : z = ~A~%" z
))
534 ((or (and (> (abs z
) 2.0) (< (abs (phase z
)) (* pi
0.9)))
535 ;; (abs z)>2.0 is necessary since there is a point
536 ;; -1.700598-0.612828*%i which 1<(abs z)<2, phase z < 0.9pi and
537 ;; still c-f expansion does not converge.
538 (and (>= (realpart z
) 0) (> (abs z
) 1.0)))
539 ;; We expand in continued fractions.
540 (when *debug-expintegral
*
541 (format t
"~&We expand in continued fractions.~%"))
543 (c (/ 1.0 (* *expint-eps
* *expint-eps
*)))
549 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
550 ((> i
*expint-maxit
*)
552 (intl:gettext
"expintegral_e: continued fractions failed.")))
555 (setq d
(/ 1.0 (+ (* a d
) b
)))
556 (setq c
(+ b
(/ a c
)))
560 (when (< (abs (- e
1.0)) *expint-eps
*)
561 (when *debug-expintegral
*
562 (setq *debug-expint-maxit
* (max *debug-expint-maxit
* i
)))
563 (return (* h
(exp (- z
))))))))
565 ;; We expand in a power series.
566 (when *debug-expintegral
*
567 (format t
"~&We expand in a power series.~%"))
569 (euler (mget '$%gamma
'$numer
))
570 (r (if (= n1
0) (- (- euler
) (log z
)) (/ 1.0 n1
)))
574 ((> i
*expint-maxit
*)
575 (merror (intl:gettext
"expintegral_e: series failed.")))
576 (setq f
(* -
1 f
(/ z i
)))
579 (let ((psi (- euler
)))
581 (setq psi
(+ psi
(/ 1.0 (+ ii
1)))))
582 (setq e
(* f
(- psi
(log z
))))))
584 (setq e
(/ (- f
) (- i n1
)))))
586 (when (< (abs e
) (* (abs r
) *expint-eps
*))
587 (when *debug-expintegral
*
588 (setq *debug-expint-maxit
* (max *debug-expint-maxit
* i
)))
591 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
592 ;;; Numerical evaluation for a real or complex parameter.
593 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
595 (defun frac-expintegral-e (n z
)
596 (declare (type (complex flonum
) n
)
597 (type (complex flonum
) z
))
599 (let ((*expint-eps
* *expint-eps
*)
600 (*expint-maxit
* *expint-maxit
*))
602 (when *debug-expintegral
*
603 (format t
"~&FRAC-EXPINTEGRAL-E called with:~%")
604 (format t
"~& : n = ~A~%" n
)
605 (format t
"~& : z = ~A~%" z
))
608 ((and (> (realpart z
) 0) (> (abs z
) 1.0))
609 ;; We expand in continued fractions.
610 (when *debug-expintegral
*
611 (format t
"~&We expand in continued fractions.~%"))
613 (c (/ 1.0 (* *expint-eps
* *expint-eps
*)))
619 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
620 ((> i
*expint-maxit
*)
622 (intl:gettext
"expintegral_e: continued fractions failed.")))
625 (setq d
(/ 1.0 (+ (* a d
) b
)))
626 (setq c
(+ b
(/ a c
)))
630 (when (< (abs (- e
1.0)) *expint-eps
*)
631 (when *debug-expintegral
*
632 (setq *debug-expint-fracmaxit
* (max *debug-expint-fracmaxit
* i
)))
633 (return (* h
(exp (- z
))))))))
635 ((and (= (imagpart n
) 0)
637 (= (nth-value 1 (truncate (realpart n
))) 0))
638 ;; We have a positive integer n or an float representation of an
639 ;; integer. We call expintegral-e which does this calculation.
640 (when *debug-expintegral
*
641 (format t
"~&We call expintegral-e.~%"))
642 (expintegral-e (truncate (realpart n
)) z
))
645 ;; At this point the parameter n is a real (not an float representation
646 ;; of an integer) or complex. We expand in a power series.
647 (when *debug-expintegral
*
648 (format t
"~&We expand in a power series.~%"))
650 ;; It would be possible to call the numerical implementation
651 ;; gamm-lanczos directly. But then the code would depend on the
652 ;; details of the implementation.
653 (gm (let ((tmp (take '(%gamma
) (complexify (- 1 n
)))))
654 (complex ($realpart tmp
) ($imagpart tmp
))))
655 (r (- (* (expt z n1
) gm
) (/ 1.0 (- 1 n
))))
659 ((> i
*expint-maxit
*)
660 (merror (intl:gettext
"expintegral_e: series failed.")))
661 (setq f
(* -
1 f
(/ z
(float i
))))
662 (setq e
(/ (- f
) (- (float i
) n1
)))
664 (when (< (abs e
) (* (abs r
) *expint-eps
*))
665 (when *debug-expintegral
*
666 (setq *debug-expint-fracmaxit
* (max *debug-expint-fracmaxit
* i
)))
669 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
670 ;;; Helper functions for Bigfloat numerical evaluation.
671 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
673 (defun cmul (x y
) ($rectform
(mul x y
)))
675 (defun cdiv (x y
) ($rectform
(div x y
)))
677 (defun cpower (x y
) ($rectform
(power x y
)))
679 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
680 ;;; We have not changed the above algorithm, but generalized it to handle
681 ;;; complex and real Bigfloat numbers. By carefully examination of the
682 ;;; algorithm some of the additional calls to $rectform can be eliminated.
683 ;;; But the algorithm works and so we leave the extra calls for later work
685 ;;; The accuracy of the result is determined by *expint-eps*. The value is
686 ;;; chosen to correspond to the value of $fpprec. We don't give any extra
687 ;;; digits to fpprec, so we loose 1 to 2 digits of precision.
688 ;;; One problem is to chose a sufficient big *expint-maxit*.
689 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
691 (defun bfloat-expintegral-e (n z
)
692 (let ((*expint-eps
* (power ($bfloat
10.0) (- $fpprec
)))
693 (*expint-maxit
* 5000) ; arbitrarily chosen, we need a better choice
694 (bigfloattwo (add bigfloatone bigfloatone
))
695 (bigfloat%e
($bfloat
'$%e
))
696 (bigfloat%gamma
($bfloat
'$%gamma
))
697 (flz (complex ($float
($realpart z
)) ($float
($imagpart z
)))))
699 (when *debug-expintegral
*
700 (format t
"~&BFLOAT-EXPINTEGRAL-E called with:~%")
701 (format t
"~& : n = ~A~%" n
)
702 (format t
"~& : z = ~A~%" flz
))
705 ((or (and (> (abs flz
) 2) (< (abs (phase flz
)) (* pi
0.9)))
706 ;; The same condition as you see in expintegral-e()
707 (and (>= (realpart flz
) 0) (> (abs flz
) 1.0)))
708 ;; We expand in continued fractions.
709 (when *debug-expintegral
*
710 (format t
"~&We expand in continued fractions.~%"))
712 (c (div bigfloatone
(mul *expint-eps
* *expint-eps
*)))
713 (d (cdiv bigfloatone b
))
718 (a (* -
1 n
) (* (- i
) (+ n1 i
))))
719 ((> i
*expint-maxit
*)
721 (intl:gettext
"expintegral_e: continued fractions failed.")))
723 (setq b
(add b bigfloattwo
))
724 (setq d
(cdiv bigfloatone
(add (mul a d
) b
)))
725 (setq c
(add b
(cdiv a c
)))
729 (when (eq ($sign
(sub (cabs (sub e bigfloatone
)) *expint-eps
*))
731 (when *debug-expintegral
*
732 (setq *debug-expint-bfloatmaxit
*
733 (max *debug-expint-bfloatmaxit
* i
)))
734 (return (cmul h
(cpower bigfloat%e
(mul -
1 z
))))))))
736 ;; We expand in a power series.
737 (when *debug-expintegral
*
738 (format t
"~&We expand in a power series.~%"))
740 (meuler (mul -
1 bigfloat%gamma
))
741 (r (if (= n1
0) (sub meuler
($log z
)) (div bigfloatone n1
)))
745 ((> i
*expint-maxit
*)
746 (merror (intl:gettext
"expintegral_e: series failed.")))
747 (setq f
(mul -
1 (cmul f
(cdiv z i
))))
752 (setq psi
(add psi
(cdiv bigfloatone
(+ ii
1)))))
753 (setq e
(cmul f
(sub psi
($log z
))))))
755 (setq e
(cdiv (mul -
1 f
) (- i n1
)))))
757 (when (eq ($sign
(sub (cabs e
) (cmul (cabs r
) *expint-eps
*)))
759 (when *debug-expintegral
*
760 (setq *debug-expint-bfloatmaxit
*
761 (max *debug-expint-bfloatmaxit
* i
)))
764 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
765 ;;; Numerical Bigfloat evaluation for a real (Bigfloat) parameter.
766 ;;; The algorithm would work for a Complex Bigfloat parameter too. But we
767 ;;; need the values of Gamma for Complex Bigfloats. This is at this time (2008)
768 ;;; not implemented in Maxima.
769 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
771 (defun frac-bfloat-expintegral-e (n z
)
772 (let ((*expint-eps
* (power ($bfloat
10.0) (- $fpprec
)))
773 (*expint-maxit
* 5000) ; arbitrarily chosen, we need a better choice
774 (bigfloattwo (add bigfloatone bigfloatone
))
775 (bigfloat%e
($bfloat
'$%e
))
776 (bigfloat%gamma
($bfloat
'$%gamma
)))
778 (when *debug-expintegral
*
779 (format t
"~&FRAC-BFLOAT-EXPINTEGRAL-E called with:~%")
780 (format t
"~& : n = ~A~%" n
)
781 (format t
"~& : z = ~A~%" z
))
784 ((and (or (eq ($sign
($realpart z
)) '$pos
)
785 (eq ($sign
($realpart z
)) '$zero
))
786 (eq ($sign
(sub (cabs z
) bigfloatone
)) '$pos
))
787 ;; We expand in continued fractions.
788 (when *debug-expintegral
*
789 (format t
"We expand in continued fractions.~%"))
791 (c (div bigfloatone
(mul *expint-eps
* *expint-eps
*)))
792 (d (cdiv bigfloatone b
))
797 (a (mul -
1 n
) (cmul (- i
) (add n1 i
))))
798 ((> i
*expint-maxit
*)
800 (intl:gettext
"expintegral_e: continued fractions failed.")))
802 (setq b
(add b bigfloattwo
))
803 (setq d
(cdiv bigfloatone
(add (mul a d
) b
)))
804 (setq c
(add b
(cdiv a c
)))
808 (when (eq ($sign
(sub (cabs (sub e bigfloatone
)) *expint-eps
*))
810 (when *debug-expintegral
*
811 (setq *debug-expint-fracbfloatmaxit
*
812 (max *debug-expint-fracbfloatmaxit
* i
)))
813 (return (cmul h
(cpower bigfloat%e
(mul -
1 z
))))))))
815 ((or (and (numberp n
)
818 (= (nth-value 1 (truncate ($realpart n
))) 0))
821 (equal (sub (mul 2 ($fix n
)) (mul 2 n
))
823 ;; We have a Float or Bigfloat representation of positive integer.
824 ;; We call bfloat-expintegral-e.
825 (when *debug-expintegral
*
826 (format t
"frac-Bigfloat with integer ~A~%" n
))
827 (bfloat-expintegral-e ($fix
($realpart n
)) z
))
830 ;; At this point the parameter n is a real (not a float representation
831 ;; of an integer) or complex. We expand in a power series.
832 (when *debug-expintegral
*
833 (format t
"We expand in a power series.~%"))
834 (let* ((n1 (sub n bigfloatone
))
835 (n2 (sub bigfloatone n
))
836 (gm (take '(%gamma
) n2
))
837 (r (sub (cmul (cpower z n1
) gm
) (cdiv bigfloatone n2
)))
841 ((> i
*expint-maxit
*)
842 (merror (intl:gettext
"expintegral_e: series failed.")))
843 (setq f
(cmul (mul -
1 bigfloatone
) (cmul f
(cdiv z i
))))
844 (setq e
(cdiv (mul -
1 f
) (sub i n1
)))
846 (when (eq ($sign
(sub (cabs e
) (cmul (cabs r
) *expint-eps
*)))
848 (when *debug-expintegral
*
849 (setq *debug-expint-fracbfloatmaxit
*
850 (max *debug-expint-fracbfloatmaxit
* i
)))
853 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
855 ;;; Part 2: The implementation of the Exponential Integral E1
857 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
859 (defmfun $expintegral_e1
(z)
860 (simplify (list '(%expintegral_e1
) z
)))
862 ;;; Set properties to give full support to the parser and display
864 (defprop $expintegral_e1 %expintegral_e1 alias
)
865 (defprop $expintegral_e1 %expintegral_e1 verb
)
867 (defprop %expintegral_e1 $expintegral_e1 reversealias
)
868 (defprop %expintegral_e1 $expintegral_e1 noun
)
870 ;;; Exponential Integral E1 is a simplifying function
872 (defprop %expintegral_e1 simp-expintegral_e1 operators
)
874 ;;; Exponential Integral E1 distributes over bags
876 (defprop %expintegral_e1
(mlist $matrix mequal
) distribute_over
)
878 ;;; Exponential Integral E1 has mirror symmetry,
879 ;;; but not on the real negative axis.
881 (defprop %expintegral_e1 conjugate-expintegral-e1 conjugate-function
)
883 (defun conjugate-expintegral-e1 (args)
884 (let ((z (first args
)))
885 (cond ((off-negative-real-axisp z
)
886 ;; Definitely not on the negative real axis for z. Mirror symmetry.
887 (take '(%expintegral_e1
) (take '($conjugate
) z
)))
889 ;; On the negative real axis or no information. Unsimplified.
890 (list '($conjugate simp
) (take '(%expintegral_e1
) z
))))))
892 ;;; Differentiation of Exponential Integral E1
894 (defprop %expintegral_e1
898 ((mexpt) $%e
((mtimes) -
1 x
))))
901 ;;; Integral of Exponential Integral E1
903 (defprop %expintegral_e1
905 ((mtimes) -
1 ((%expintegral_e
) 2 z
)))
908 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
910 ;;; We support a simplim%function. The function is looked up in simplimit and
911 ;;; handles specific values of the function.
913 (defprop %expintegral_e1 simplim%expintegral_e1 simplim%function
)
915 (defun simplim%expintegral_e1
(expr var val
)
916 ;; Look for the limit of the argument.
917 (let ((z (limit (cadr expr
) var val
'think
)))
919 ;; Handle an argument 0 at this place
923 ;; limit is inf from both sides
926 ;; All other cases are handled by the simplifier of the function.
927 (take '(%expintegral_e1
) z
)))))
929 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
931 (defun simp-expintegral_e1 (expr ignored z
)
932 (declare (ignore ignored
))
934 (let ((arg (simpcheck (cadr expr
) z
)))
936 ;; Check for special values
938 (alike1 arg
'((mtimes) -
1 $minf
)))
942 (intl:gettext
"expintegral_e1: expintegral_e1(~:M) is undefined.") arg
))
944 ;; Check for numerical evaluation
945 ((complex-float-numerical-eval-p arg
)
946 ;; For E1 we call En(z) with n=1 directly.
947 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
948 (complexify (expintegral-e 1 carg
))))
950 ((complex-bigfloat-numerical-eval-p arg
)
951 ;; For E1 we call En(z) with n=1 directly.
952 (let* (($ratprint nil
)
953 (carg (add ($bfloat
($realpart arg
))
954 (mul '$%i
($bfloat
($imagpart arg
)))))
955 (result (bfloat-expintegral-e 1 carg
)))
956 (add ($realpart result
)
957 (mul '$%i
($imagpart result
)))))
959 ;; Check argument simplifications and transformations
960 ((taylorize (mop expr
) (second expr
)))
963 (member $expintrep
*expintflag
* :test
#'eq
)
964 (not (eq $expintrep
'%expintegral_e1
)))
967 (take '(%gamma_incomplete
) 0 arg
))
969 (add (mul -
1 (take '(%expintegral_ei
) (mul -
1 arg
)))
971 (sub (take '(%log
) (mul -
1 arg
))
972 (take '(%log
) (mul -
1 (inv arg
)))))
973 (mul -
1 (take '(%log
) arg
))))
975 (add (mul -
1 (take '(%expintegral_li
) (power '$%e
(mul -
1 arg
))))
976 (mul -
1 (take '(%log
) arg
))
978 (sub (take '(%log
) (mul -
1 arg
))
979 (take '(%log
) (mul -
1 (inv arg
)))))))
981 (add (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i arg
)))
982 (mul -
1 (take '(%expintegral_ci
) (mul '$%i arg
)))
983 (take '(%log
) (mul '$%i arg
))
984 (mul -
1 (take '(%log
) arg
))))
986 (sub (take '(%expintegral_shi
) arg
)
987 (take '(%expintegral_chi
) arg
)))
989 (eqtest (list '(%expintegral_e1
) arg
) expr
))))
992 (eqtest (list '(%expintegral_e1
) arg
) expr
)))))
994 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
996 ;;; Part 3: The implementation of the Exponential Integral Ei
998 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1000 (defmfun $expintegral_ei
(z)
1001 (simplify (list '(%expintegral_ei
) z
)))
1003 ;;; Set properties to give full support to the parser and display
1005 (defprop $expintegral_ei %expintegral_ei alias
)
1006 (defprop $expintegral_ei %expintegral_ei verb
)
1008 (defprop %expintegral_ei $expintegral_ei reversealias
)
1009 (defprop %expintegral_ei $expintegral_ei noun
)
1011 ;;; Exponential Integral Ei is a simplifying function
1013 (defprop %expintegral_ei simp-expintegral-ei operators
)
1015 ;;; Exponential Integral Ei distributes over bags
1017 (defprop %expintegral_ei
(mlist $matrix mequal
) distribute_over
)
1019 ;;; Exponential Integral Ei has mirror symmetry
1021 (defprop %expintegral_ei t commutes-with-conjugate
)
1023 ;;; Differentiation of Exponential Integral Ei
1025 (defprop %expintegral_ei
1027 ((mtimes) ((mexpt) x -
1) ((mexpt) $%e x
)))
1030 ;;; Integral of Exponential Ei
1032 (defprop %expintegral_ei
1035 ((mtimes) -
1 ((mexpt) $%e x
))
1036 ((mtimes) x
((%expintegral_ei
) x
))))
1039 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1041 ;;; We support a simplim%function. The function is looked up in simplimit and
1042 ;;; handles specific values of the function.
1044 (defprop %expintegral_ei simplim%expintegral_ei simplim%function
)
1046 (defun simplim%expintegral_ei
(expr var val
)
1047 ;; Look for the limit of the arguments.
1048 (let ((z (limit (cadr expr
) var val
'think
)))
1050 ;; Handle an argument 0 at this place
1056 ;; All other cases are handled by the simplifier of the function.
1057 (take '(%expintegral_ei
) z
)))))
1059 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1061 (defun simp-expintegral-ei (expr ignored z
)
1062 (declare (ignore ignored
))
1064 (let ((arg (simpcheck (cadr expr
) z
)))
1066 ;; Check special values
1069 (intl:gettext
"expintegral_ei: expintegral_ei(~:M) is undefined.")
1072 (alike1 arg
'((mtimes) -
1 $minf
)))
1074 ((or (eq arg
'$minf
)
1075 (alike1 arg
'((mtimes) -
1 $inf
)))
1077 ((or (alike1 arg
'((mtimes) $%i $inf
))
1078 (alike1 arg
'((mtimes) -
1 $%i $minf
)))
1080 ((or (alike1 arg
'((mtimes) $%i $minf
))
1081 (alike1 arg
'((mtimes) -
1 $%i $inf
)))
1082 (mul -
1 '$%i
'$%pi
))
1084 ;; Check numerical evaluation
1085 ((complex-float-numerical-eval-p arg
)
1086 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1087 (complexify (expintegral-ei carg
))))
1089 ((complex-bigfloat-numerical-eval-p arg
)
1090 (let* (($ratprint nil
)
1091 (carg (add ($bfloat
($realpart arg
))
1092 (mul '$%i
($bfloat
($imagpart arg
)))))
1093 (result (bfloat-expintegral-ei carg
)))
1094 (add ($realpart result
)
1095 (mul '$%i
($imagpart result
)))))
1097 ;; Check argument simplifications and transformations
1098 ((taylorize (mop expr
) (second expr
)))
1101 (member $expintrep
*expintflag
*)
1102 (not (eq $expintrep
'%expintegral_ei
)))
1105 (add (mul -
1 (take '(%gamma_incomplete
) 0 (mul -
1 arg
)))
1107 (sub (take '(%log
) arg
)
1108 (take '(%log
) (inv arg
))))
1109 (mul -
1 (take '(%log
) (mul -
1 arg
)))))
1111 (add (mul -
1 (take '(%expintegral_e1
) (mul -
1 arg
)))
1113 (sub (take '(%log
) arg
)
1114 (take '(%log
) (inv arg
))))
1115 (mul -
1 (take '(%log
) (mul -
1 arg
)))))
1117 (take '(%expintegral_li
) (power '$%e arg
)))
1119 (add (take '(%expintegral_ci
) (mul '$%i arg
))
1120 (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i arg
)))
1122 (sub (take '(%log
) (inv arg
))
1123 (take '(%log
) arg
)))
1124 (mul -
1 (take '(%log
) (mul '$%i arg
)))))
1126 (add (take '(%expintegral_chi
) arg
)
1127 (take '(%expintegral_shi
) arg
)
1129 (add (take '(%log
) (inv arg
))
1130 (take '(%log
) arg
)))))))
1133 (eqtest (list '(%expintegral_ei
) arg
) expr
)))))
1135 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1136 ;;; Numerical evaluation of the Exponential Integral Ei(z):
1138 ;;; We use the following representation (see functions.wolfram.com):
1140 ;;; Ei(z) = -E1(-z) + 0.5*(log(z)-log(1/z))-log(-z)
1142 ;;; z is a CL Complex number. Because we evaluate for Complex values we have to
1143 ;;; take into account the complete Complex phase factors.
1144 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1146 (defun expintegral-ei (z)
1147 (+ (- (expintegral-e 1 (- z
)))
1148 ;; Carefully compute 1/2*(log(z)-log(1/z))-log(-z), using the
1149 ;; branch cuts that we want, not the one that Lisp wants.
1150 ;; (Mostly an issue with Lisps that support signed zeroes.)
1153 ;; Positive imaginary part. Add phase %i*%pi.
1154 (complex 0 (float pi
)))
1156 ;; Negative imaginary part. Add phase -%i*%pi.
1157 (complex 0 (- (float pi
))))
1159 ;; Positive real value. Add phase -%i*pi.
1160 (complex 0 (- (float pi
))))
1161 ;; Negative real value. No phase factor.
1164 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1165 ;;; We have not modified the algorithm for Bigfloat numbers. It is only
1166 ;;; generalized for Bigfloats. The calcualtion of the complex phase factor
1167 ;;; can be simplified to conditions about the sign of the realpart and
1168 ;;; imagpart. We leave this for further work to optimize the speed of the
1170 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1172 (defun bfloat-expintegral-ei (z)
1173 (let ((mz (mul -
1 z
)))
1174 (add (cmul (mul -
1 bigfloatone
)
1175 (bfloat-expintegral-e 1 mz
))
1176 (sub (cmul (div bigfloatone
2)
1177 (sub (take '(%log
) z
)
1178 (take '(%log
) (cdiv bigfloatone z
))))
1179 (take '(%log
) mz
)))))
1181 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1183 ;;; Part 4: The implementation of the Logarithmic integral li(z)
1185 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1187 (defmfun $expintegral_li
(z)
1188 (simplify (list '(%expintegral_li
) z
)))
1190 ;;; Set properties to give full support to the parser and display
1192 (defprop $expintegral_li %expintegral_li alias
)
1193 (defprop $expintegral_li %expintegral_li verb
)
1195 (defprop %expintegral_li $expintegral_li reversealias
)
1196 (defprop %expintegral_li $expintegral_li noun
)
1198 ;;; Exponential Integral Li is a simplifying function
1200 (defprop %expintegral_li simp-expintegral-li operators
)
1202 ;;; Exponential Integral Li distributes over bags
1204 (defprop %expintegral_li
(mlist $matrix mequal
) distribute_over
)
1206 ;;; Exponential Integral Li has mirror symmetry,
1207 ;;; but not on the real negative axis.
1209 (defprop %expintegral_li conjugate-expintegral-li conjugate-function
)
1211 (defun conjugate-expintegral-li (args)
1212 (let ((z (first args
)))
1213 (cond ((off-negative-real-axisp z
)
1214 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1215 (take '(%expintegral_li
) (take '($conjugate
) z
)))
1217 ;; On the negative real axis or no information. Unsimplified.
1218 (list '($conjugate simp
) (take '(%expintegral_li
) z
))))))
1220 ;;; Differentiation of Exponential Integral Li
1222 (defprop %expintegral_li
1224 ((mtimes) ((mexpt) ((%log
) x
) -
1)))
1227 ;;; Integral of Exponential Li
1229 (defprop %expintegral_li
1232 ((mtimes) x
((%expintegral_li
) x
))
1233 ((mtimes) -
1 ((%expintegral_ei
) ((mtimes) 2 ((%log
) x
))))))
1236 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1238 ;;; We support a simplim%function. The function is looked up in simplimit and
1239 ;;; handles specific values of the function.
1241 (defprop %expintegral_li simplim%expintegral_li simplim%function
)
1243 (defun simplim%expintegral_li
(expr var val
)
1244 ;; Look for the limit of the argument.
1245 (let ((z (limit (cadr expr
) var val
'think
)))
1247 ;; Handle an argument 1 at this place
1250 ;; All other cases are handled by the simplifier of the function.
1251 (take '(%expintegral_li
) z
)))))
1253 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1255 (defun simp-expintegral-li (expr ignored z
)
1256 (declare (ignore ignored
))
1258 (let ((arg (simpcheck (cadr expr
) z
)))
1263 (intl:gettext
"expintegral_li: expintegral_li(~:M) is undefined.") arg
))
1265 (alike1 arg
'((mtimes) -
1 $minf
)))
1267 ((eq arg
'$infinity
) '$infinity
)
1269 ((complex-float-numerical-eval-p arg
)
1270 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1271 (complexify (expintegral-li carg
))))
1273 ((complex-bigfloat-numerical-eval-p arg
)
1274 (let* (($ratprint nil
)
1275 (carg (add ($bfloat
($realpart arg
))
1276 (mul '$%i
($bfloat
($imagpart arg
)))))
1277 (result (bfloat-expintegral-li carg
)))
1278 (add (mul '$%i
($imagpart result
))
1279 ($realpart result
))))
1281 ;; Check for argument simplifications and transformations
1282 ((taylorize (mop expr
) (second expr
)))
1285 (member $expintrep
*expintflag
*)
1286 (not (eq $expintrep
'%expintegral_li
)))
1287 (let ((logarg (take '(%log
) arg
)))
1290 (add (mul -
1 (take '(%gamma_incomplete
) 0 (mul -
1 logarg
)))
1292 (sub (take '(%log
) logarg
)
1293 (take '(%log
) (inv logarg
))))
1294 (mul -
1 (take '(%log
) (mul -
1 logarg
)))))
1296 (add (mul -
1 (take '(%expintegral_e1
) (mul -
1 logarg
)))
1298 (sub (take '(%log
) logarg
)
1299 (take '(%log
) (inv logarg
))))
1300 (mul -
1 (take '(%log
) (mul -
1 logarg
)))))
1302 ($expintegral_ei logarg
))
1304 (add (take '(%expintegral_ci
) (mul '$%i logarg
))
1305 (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i logarg
)))
1307 (sub (take '(%log
) (inv logarg
))
1308 (take '(%log
) logarg
)))
1309 (mul -
1 (take '(%log
) (mul '$%i logarg
)))))
1311 (add (take '(%expintegral_chi
) logarg
)
1312 (take '(%expintegral_shi
) logarg
)
1314 (add (take '(%log
) (inv logarg
))
1315 (take '(%log
) logarg
))))))))
1318 (eqtest (list '(%expintegral_li
) arg
) expr
)))))
1320 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1321 ;;; Numerical evaluation of the Expintegral Li
1323 ;;; We use the representation:
1325 ;;; Li(z) = Ei(log(z))
1326 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1328 (defun expintegral-li (z)
1329 (expintegral-ei (log z
)))
1331 (defun bfloat-expintegral-li (z)
1332 (bfloat-expintegral-ei ($log z
)))
1334 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1336 ;;; Part 5: The implementation of the Exponential Integral Si
1338 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1340 (defmfun $expintegral_si
(z)
1341 (simplify (list '(%expintegral_si
) z
)))
1343 ;;; Set properties to give full support to the parser and display
1345 (defprop $expintegral_si %expintegral_si alias
)
1346 (defprop $expintegral_si %expintegral_si verb
)
1348 (defprop %expintegral_si $expintegral_si reversealias
)
1349 (defprop %expintegral_si $expintegral_si noun
)
1351 ;;; Exponential Integral Si is a simplifying function
1353 (defprop %expintegral_si simp-expintegral-si operators
)
1355 ;;; Exponential Integral Si distributes over bags
1357 (defprop %expintegral_si
(mlist $matrix mequal
) distribute_over
)
1359 ;;; Exponential Integral Si has mirror symmetry
1361 (defprop %expintegral_si t commutes-with-conjugate
)
1363 ;;; Exponential Integral Si is a odd function
1365 (defprop %expintegral_si odd-function-reflect reflection-rule
)
1367 ;;; Differentiation of Exponential Integral Si
1369 (defprop %expintegral_si
1371 ((mtimes) ((%sin
) x
) ((mexpt) x -
1)))
1374 ;;; Integral of Exponential Si
1376 (defprop %expintegral_si
1380 ((mtimes) x
((%expintegral_si
) x
))))
1383 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1385 ;;; We support a simplim%function.
1387 (defprop %expintegral_si simplim%expintegral_si simplim%function
)
1389 (defun simplim%expintegral_si
(expr var val
)
1390 ;; Look for the limit of the argument.
1391 (let ((z (limit (cadr expr
) var val
'think
)))
1392 ;; All cases are handled by the simplifier of the function.
1393 (take '(%expintegral_si
) z
)))
1395 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1397 (defun simp-expintegral-si (expr ignored z
)
1398 (declare (ignore ignored
))
1400 (let ((arg (simpcheck (cadr expr
) z
)))
1402 ;; Check for special values
1405 (alike1 arg
'((mtimes) -
1 $minf
)))
1407 ((or (eq arg
'$minf
)
1408 (alike1 arg
'((mtimes) -
1 $inf
)))
1409 (mul -
1 (div '$%pi
2)))
1411 ;; Check for numerical evaluation
1412 ((complex-float-numerical-eval-p arg
)
1413 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1414 (complexify (expintegral-si carg
))))
1416 ((complex-bigfloat-numerical-eval-p arg
)
1417 (let* (($ratprint nil
)
1418 (carg (add ($bfloat
($realpart arg
))
1419 (mul '$%i
($bfloat
($imagpart arg
)))))
1420 (result (bfloat-expintegral-si carg
)))
1421 (add (mul '$%i
($imagpart result
))
1422 ($realpart result
))))
1424 ;; Check for argument simplifications and transformations
1425 ((taylorize (mop expr
) (second expr
)))
1426 ((apply-reflection-simp (mop expr
) arg $trigsign
))
1429 (member $expintrep
*expintflag
*)
1430 (not (eq $expintrep
'$expintegral_trig
)))
1434 (add (take '(%gamma_incomplete
) 0 (mul -
1 '$%i arg
))
1435 (mul -
1 (take '(%gamma_incomplete
) 0 (mul '$%i arg
)))
1436 (take '(%log
) (mul -
1 '$%i arg
))
1437 (mul -
1 (take '(%log
) (mul '$%i arg
))))))
1440 (add (take '(%expintegral_e1
) (mul -
1 '$%i arg
))
1441 (mul -
1 (take '(%expintegral_e1
) (mul '$%i arg
)))
1442 (take '(%log
) (mul -
1 '$%i arg
))
1443 (mul -
1 (take '(%log
) (mul '$%i arg
))))))
1447 (sub (take '(%expintegral_ei
) (mul -
1 '$%i arg
))
1448 (take '(%expintegral_ei
) (mul '$%i arg
))))
1449 (take '(%log
) (div '$%i arg
))
1450 (mul -
1 (take '(%log
) (mul -
1 (div '$%i arg
))))
1451 (mul -
1 (take '(%log
) (mul -
1 '$%i arg
)))
1452 (take '(%log
) (mul '$%i arg
)))))
1454 (mul (inv (mul 2 '$%i
))
1455 (add (take '(%expintegral_li
) (power '$%e
(mul '$%i arg
)))
1457 (take '(%expintegral_li
)
1458 (power '$%e
(mul -
1 '$%e arg
))))
1460 (take '(%signum
) ($realpart arg
))))))
1462 (mul -
1 '$%i
(take '(%expintegral_shi
) (mul '$%i arg
))))))
1465 (eqtest (list '(%expintegral_si
) arg
) expr
)))))
1467 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1468 ;;; Numerical evaluation of the Exponential Integral Si
1470 ;;; We use the representation:
1472 ;;; Si(z) = %i/2 * (E1(-%i*z) - E1(*%i*z) + log(%i*z) - log(-%i*z))
1474 ;;; For the Sin, Cos, Sinh and Cosh Exponential Integrals we have to call the
1475 ;;; numerical evaluation twice. In principle we could use a direct expansion
1476 ;;; in a power series or continued fractions to optimize the speed of the code.
1477 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1479 (defun expintegral-si (z)
1480 (let ((z (coerce z
'(complex flonum
))))
1482 (+ (expintegral-e 1 (* (complex 0 -
1) z
))
1483 (- (expintegral-e 1 (* (complex 0 1) z
)))
1484 (log (* (complex 0 -
1) z
))
1485 (- (log (* (complex 0 1) z
)))))))
1487 (defun bfloat-expintegral-si (z)
1488 (let ((z*%i
(cmul '$%i z
))
1489 (mz*%i
(cmul (mul -
1 '$%i
) z
)))
1493 (bfloat-expintegral-e 1 mz
*%i
)
1494 (mul -
1 (bfloat-expintegral-e 1 z
*%i
))
1496 (mul -
1 ($log z
*%i
))))))
1498 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1500 ;;; Part 6: The implementation of the Exponential Integral Shi
1502 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1504 (defmfun $expintegral_shi
(z)
1505 (simplify (list '(%expintegral_shi
) z
)))
1507 ;;; Set properties to give full support to the parser and display
1509 (defprop $expintegral_shi %expintegral_shi alias
)
1510 (defprop $expintegral_shi %expintegral_shi verb
)
1512 (defprop %expintegral_shi $expintegral_shi reversealias
)
1513 (defprop %expintegral_shi $expintegral_shi noun
)
1515 ;;; Exponential Integral Shi is a simplifying function
1517 (defprop %expintegral_shi simp-expintegral-shi operators
)
1519 ;;; Exponential Integral Shi distributes over bags
1521 (defprop %expintegral_shi
(mlist $matrix mequal
) distribute_over
)
1523 ;;; Exponential Integral Shi has mirror symmetry
1525 (defprop %expintegral_si t commutes-with-conjugate
)
1527 ;;; Exponential Integral Shi is a odd function
1529 (defprop %expintegral_si odd-function-reflect reflection-rule
)
1531 ;;; Differentiation of Exponential Integral Shi
1533 (defprop %expintegral_shi
1535 ((mtimes) ((%sinh
) x
) ((mexpt) x -
1)))
1538 ;;; Integral of Exponential Shi
1540 (defprop %expintegral_shi
1543 ((mtimes) -
1 ((%cosh
) x
))
1544 ((mtimes) x
((%expintegral_shi
) x
))))
1547 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1549 ;;; We support a simplim%function. The function is looked up in simplimit and
1550 ;;; handles specific values of the function.
1552 (defprop %expintegral_shi simplim%expintegral_shi simplim%function
)
1554 (defun simplim%expintegral_shi
(expr var val
)
1555 ;; Look for the limit of the argument.
1556 (let ((z (limit (cadr expr
) var val
'think
)))
1558 ;; Handle infinities at this place
1564 ;; All other cases are handled by the simplifier of the function.
1565 (take '(%expintegral_shi
) z
)))))
1567 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1569 (defun simp-expintegral-shi (expr ignored z
)
1570 (declare (ignore ignored
))
1572 (let ((arg (simpcheck (cadr expr
) z
)))
1574 ;; Check for special values
1576 ((or (alike1 arg
'((mtimes) $%i $inf
))
1577 (alike1 arg
'((mtimes) -
1 $%i $minf
)))
1578 (div (mul '$%i
'$%pi
) 2))
1579 ((or (alike1 arg
'((mtimes) $%i $minf
))
1580 (alike1 arg
'((mtimes) -
1 $%i $inf
)))
1581 (div (mul -
1 '$%i
'$%pi
) 2))
1583 ;; Check for numrical evaluation
1584 ((float-numerical-eval-p arg
)
1585 (realpart (expintegral-shi arg
)))
1587 ((complex-float-numerical-eval-p arg
)
1588 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1589 (complexify (expintegral-shi carg
))))
1591 ((complex-bigfloat-numerical-eval-p arg
)
1592 (let* (($ratprint nil
)
1593 (carg (add ($bfloat
($realpart arg
))
1594 (mul '$%i
($bfloat
($imagpart arg
)))))
1595 (result (bfloat-expintegral-shi carg
)))
1596 (add (mul '$%i
($imagpart result
))
1597 ($realpart result
))))
1599 ;; Check for argument simplifications and transformations
1600 ((taylorize (mop expr
) (second expr
)))
1601 ((apply-reflection-simp (mop expr
) arg $trigsign
))
1604 (member $expintrep
*expintflag
*)
1605 (not (eq $expintrep
'$expintegral_hyp
)))
1609 (add (take '(%gamma_incomplete
) 0 arg
)
1610 (mul -
1 (take '(%gamma_incomplete
) 0 (mul -
1 arg
)))
1611 (mul -
1 (take '(%log
) (mul -
1 arg
)))
1612 (take '(%log
) arg
))))
1615 (add (take '(%expintegral_e1
) arg
)
1616 (mul -
1 (take '(%expintegral_e1
) (mul -
1 arg
)))
1617 (mul -
1 (take '(%log
) (mul -
1 arg
)))
1618 (take '(%log
) arg
))))
1622 (sub (take '(%expintegral_ei
) arg
)
1623 (take '(%expintegral_ei
) (mul -
1 arg
))))
1624 (take '(%log
) (inv arg
))
1625 (mul -
1 (take '(%log
) (mul -
1 (inv arg
))))
1626 (take '(%log
) (mul -
1 arg
))
1627 (mul -
1 (take '(%log
) arg
)))))
1630 (sub (take '(%expintegral_li
) (power '$%e arg
))
1631 (take '(%expintegral_li
) (power '$%e
(mul -
1 arg
)))))
1632 (mul (div (mul '$%i
'$%pi
) -
2)
1633 (take '(%signum
) ($imagpart arg
)))))
1635 (mul -
1 '$%i
(take '(%expintegral_si
) (mul '$%i arg
))))))
1638 (eqtest (list '(%expintegral_shi
) arg
) expr
)))))
1640 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1641 ;;; Numerical evaluation of the Exponential Integral Shi
1643 ;;; We use the representation:
1645 ;;; Shi(z) = 1/2 * (E1(z) - E1(-z) - log(-z) + log(z))
1647 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1649 (defun expintegral-shi (z)
1654 (- (expintegral-e 1 (- z
)))
1658 (defun bfloat-expintegral-shi (z)
1659 (let ((mz (mul -
1 z
)))
1663 (bfloat-expintegral-e 1 z
)
1664 (mul -
1 (bfloat-expintegral-e 1 mz
))
1668 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1670 ;;; Part 7: The implementation of the Exponential Integral Ci
1672 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1674 (defmfun $expintegral_ci
(z)
1675 (simplify (list '(%expintegral_ci
) z
)))
1677 ;;; Set properties to give full support to the parser and display
1679 (defprop $expintegral_ci %expintegral_ci alias
)
1680 (defprop $expintegral_ci %expintegral_ci verb
)
1682 (defprop %expintegral_ci $expintegral_ci reversealias
)
1683 (defprop %expintegral_ci $expintegral_ci noun
)
1685 ;;; Exponential Integral Ci is a simplifying function
1687 (defprop %expintegral_ci simp-expintegral-ci operators
)
1689 ;;; Exponential Integral Ci distributes over bags
1691 (defprop %expintegral_ci
(mlist $matrix mequal
) distribute_over
)
1693 ;;; Exponential Integral Ci has mirror symmetry,
1694 ;;; but not on the real negative axis.
1696 (defprop %expintegral_ci conjugate-expintegral-ci conjugate-function
)
1698 (defun conjugate-expintegral-ci (args)
1699 (let ((z (first args
)))
1700 (cond ((off-negative-real-axisp z
)
1701 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1702 (take '(%expintegral_ci
) (take '($conjugate
) z
)))
1704 ;; On the negative real axis or no information. Unsimplified.
1705 (list '($conjugate simp
) (take '(%expintegral_ci
) z
))))))
1707 ;;; Differentiation of Exponential Integral Ci
1709 (defprop %expintegral_ci
1711 ((mtimes) ((%cos
) x
) ((mexpt) x -
1)))
1714 ;;; Integral of Exponential Ci
1716 (defprop %expintegral_ci
1719 ((mtimes) x
((%expintegral_ci
) x
))
1720 ((mtimes) -
1 ((%sin
) x
))))
1723 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1725 ;;; We support a simplim%function. The function is looked up in simplimit and
1726 ;;; handles specific values of the function.
1728 (defprop %expintegral_ci simplim%expintegral_ci simplim%function
)
1730 (defun simplim%expintegral_ci
(expr var val
)
1731 ;; Look for the limit of the argument.
1732 (let ((z (limit (cadr expr
) var val
'think
)))
1734 ;; Handle an argument 0 at this place
1740 ;; All other cases are handled by the simplifier of the function.
1741 (take '(%expintegral_ci
) z
)))))
1743 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1745 (defun simp-expintegral-ci (expr ignored z
)
1746 (declare (ignore ignored
))
1748 (let ((arg (simpcheck (cadr expr
) z
)))
1750 ;; Check for special values
1753 (intl:gettext
"expintegral_ci: expintegral_ci(~:M) is undefined.") arg
))
1755 (alike1 arg
'((mtimes) -
1 $minf
)))
1757 ((or (eq arg
'$minf
)
1758 (alike1 arg
'((mtimes) -
1 $inf
)))
1761 ;; Check for numerical evaluation
1762 ((complex-float-numerical-eval-p arg
)
1763 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1764 (complexify (expintegral-ci carg
))))
1766 ((complex-bigfloat-numerical-eval-p arg
)
1767 (let* (($ratprint nil
)
1768 (carg (add ($bfloat
($realpart arg
))
1769 (mul '$%i
($bfloat
($imagpart arg
)))))
1770 (result (bfloat-expintegral-ci carg
)))
1771 (add (mul '$%i
($imagpart result
))
1772 ($realpart result
))))
1774 ;; Check for argument simplifications and transformations
1775 ((taylorize (mop expr
) (second expr
)))
1778 (member $expintrep
*expintflag
*)
1779 (not (eq $expintrep
'$expintegral_trig
)))
1782 (sub (take '(%log
) arg
)
1784 (add (take '(%gamma_incomplete
) 0 (mul -
1 '$%i arg
))
1785 (take '(%gamma_incomplete
) 0 (mul '$%i arg
))
1786 (take '(%log
) (mul -
1 '$%i arg
))
1787 (take '(%log
) (mul '$%i arg
))))))
1790 (add (take '(%expintegral_e1
) (mul -
1 '$%i arg
))
1791 (take '(%expintegral_e1
) (mul '$%i arg
)))
1792 (take '(%log
) (mul -
1 '$%i arg
))
1793 (take '(%log
) (mul '$%i arg
)))
1794 (take '(%log
) arg
)))
1798 (add (take '(%expintegral_ei
) (mul -
1 '$%i arg
))
1799 (take '(%expintegral_ei
) (mul '$%i arg
))))
1800 (take '(%log
) (div '$%i arg
))
1801 (take '(%log
) (mul -
1 '$%i
(inv arg
)))
1802 (mul -
1 (take '(%log
) (mul -
1 '$%i arg
)))
1803 (mul -
1 (take '(%log
) (mul '$%i arg
)))))
1804 (take '(%log
) arg
)))
1807 (add (take '(%expintegral_li
)
1808 (power '$%e
(mul -
1 '$%i arg
)))
1809 (take '(%expintegral_li
)
1810 (power '$%e
(mul '$%i arg
)))))
1811 (mul (div (mul '$%i
'$%pi
) 2)
1812 (take '(%signum
) ($imagpart arg
)))
1813 (sub 1 (take '(%signum
) ($realpart arg
)))))
1815 (add (take '(%expintegral_chi
) (mul '$%i arg
))
1816 (mul -
1 (take '(%log
) (mul '$%i arg
)))
1817 (take '(%log
) arg
)))))
1820 (eqtest (list '(%expintegral_ci
) arg
) expr
)))))
1822 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1823 ;;; Numerical evaluation of the Exponential Integral Ci
1825 ;;; We use the representation:
1827 ;;; Ci(z) = -1/2 * (E1(-%i*z) + E1(%i*z) + log(-%i*z) + log(%i*z)) + log(z)
1829 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1831 (defun expintegral-ci (z)
1832 (let ((z (coerce z
'(complex flonum
))))
1834 (+ (expintegral-e 1 (* (complex 0 -
1) z
))
1835 (expintegral-e 1 (* (complex 0 1) z
))
1836 (log (* (complex 0 -
1) z
))
1837 (log (* (complex 0 1) z
))))
1840 (defun bfloat-expintegral-ci (z)
1841 (let ((z*%i
(cmul '$%i z
))
1842 (mz*%i
(cmul (mul -
1 '$%i
) z
)))
1847 (bfloat-expintegral-e 1 mz
*%i
)
1848 (bfloat-expintegral-e 1 z
*%i
)
1853 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1855 ;;; Part 8: The implementation of the Exponential Integral Chi
1857 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1859 (defmfun $expintegral_chi
(z)
1860 (simplify (list '(%expintegral_chi
) z
)))
1862 ;;; Set properties to give full support to the parser and display
1864 (defprop $expintegral_chi %expintegral_chi alias
)
1865 (defprop $expintegral_chi %expintegral_chi verb
)
1867 (defprop %expintegral_chi $expintegral_chi reversealias
)
1868 (defprop %expintegral_chi $expintegral_chi noun
)
1870 ;;; Exponential Integral Chi is a simplifying function
1872 (defprop %expintegral_chi simp-expintegral-chi operators
)
1874 ;;; Exponential Integral Chi distributes over bags
1876 (defprop %expintegral_chi
(mlist $matrix mequal
) distribute_over
)
1878 ;;; Exponential Integral Chi has mirror symmetry,
1879 ;;; but not on the real negative axis.
1881 (defprop %expintegral_chi conjugate-expintegral-chi conjugate-function
)
1883 (defun conjugate-expintegral-chi (args)
1884 (let ((z (first args
)))
1885 (cond ((off-negative-real-axisp z
)
1886 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1887 (take '(%expintegral_chi
) (take '($conjugate
) z
)))
1889 ;; On the negative real axis or no information. Unsimplified.
1890 (list '($conjugate simp
) (take '(%expintegral_chi
) z
))))))
1892 ;;; Differentiation of Exponential Integral Chi
1894 (defprop %expintegral_chi
1896 ((mtimes) ((%cosh
) x
) ((mexpt) x -
1)))
1899 ;;; Integral of Exponential Chi
1901 (defprop %expintegral_chi
1904 ((mtimes) x
((%expintegral_chi
) x
))
1905 ((mtimes) -
1 ((%sinh
) x
))))
1908 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1910 ;;; We support a simplim%function. The function is looked up in simplimit and
1911 ;;; handles specific values of the function.
1913 (defprop %expintegral_chi simplim%expintegral_chi simplim%function
)
1915 (defun simplim%expintegral_chi
(expr var val
)
1916 ;; Look for the limit of the argument.
1917 (let ((z (limit (cadr expr
) var val
'think
)))
1919 ;; Handle an argument 0 at this place
1928 ;; All other cases are handled by the simplifier of the function.
1929 (take '(%expintegral_chi
) z
)))))
1931 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1933 (defun simp-expintegral-chi (expr ignored z
)
1934 (declare (ignore ignored
))
1936 (let ((arg (simpcheck (cadr expr
) z
)))
1938 ;; Check for special values
1940 ;; First check for zero argument. Throw Maxima error.
1942 (intl:gettext
"expintegral_chi: expintegral_chi(~:M) is undefined.")
1944 ((or (alike1 arg
'((mtimes) $%i $inf
))
1945 (alike1 arg
'((mtimes) -
1 $%i $minf
)))
1946 (div (mul '$%pi
'$%i
) 2))
1947 ((or (alike1 arg
'((mtimes) $%i $minf
))
1948 (alike1 arg
'((mtimes) -
1 $%i $inf
)))
1949 (div (mul -
1 '$%pi
'$%i
) 2))
1951 ;; Check for numerical evaluation
1952 ((complex-float-numerical-eval-p arg
)
1953 (let ((carg (complex ($float
($realpart arg
)) ($float
($imagpart arg
)))))
1954 (complexify (expintegral-chi carg
))))
1956 ((complex-bigfloat-numerical-eval-p arg
)
1957 (let* (($ratprint nil
)
1958 (carg (add ($bfloat
($realpart arg
))
1959 (mul '$%i
($bfloat
($imagpart arg
)))))
1960 (result (bfloat-expintegral-chi carg
)))
1961 (add (mul '$%i
($imagpart result
))
1962 ($realpart result
))))
1964 ;; Check for argument simplifications and transformations
1965 ((taylorize (mop expr
) (second expr
)))
1968 (member $expintrep
*expintflag
*)
1969 (not (eq $expintrep
'$expintegral_hyp
)))
1973 (add (take '(%gamma_incomplete
) 0 (mul -
1 arg
))
1974 (take '(%gamma_incomplete
) 0 arg
)
1975 (take '(%log
) (mul -
1 arg
))
1976 (mul -
1 (take '(%log
) arg
)))))
1979 (add (take '(%expintegral_e1
) (mul -
1 arg
))
1980 (take '(%expintegral_e1
) arg
)
1981 (take '(%log
) (mul -
1 arg
))
1982 (mul -
1 (take '(%log
) arg
)))))
1986 (add (take '(%expintegral_ei
) (mul -
1 arg
))
1987 (take '(%expintegral_ei
) arg
)))
1988 (take '(%log
) (inv arg
))
1989 (take '(%log
) (mul -
1 (inv arg
)))
1990 (mul -
1 (take '(%log
) (mul -
1 arg
)))
1991 (mul 3 (take '(%log
) arg
)))))
1994 (add (take '(%expintegral_li
) (power '$%e
(mul -
1 arg
)))
1995 (take '(%expintegral_li
) (power '$%e arg
))))
1996 (mul (div (mul '$%i
'$%pi
) 2)
1997 (take '(%signum
) ($imagpart arg
)))
1999 (add (take '(%log
) (inv arg
))
2000 (take '(%log
) arg
)))))
2002 (add (take '(%expintegral_ci
) (mul '$%i arg
))
2004 (mul -
1 (take '(%log
) (mul '$%i arg
)))))))
2007 (eqtest (list '(%expintegral_chi
) arg
) expr
)))))
2009 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2010 ;;; Numerical evaluation of the Exponential Integral Ci
2012 ;;; We use the representation:
2014 ;;; Chi(z) = -1/2 * (E1(-z) + E1(z) + log(-z) - log(z))
2016 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2018 (defun expintegral-chi (z)
2023 (expintegral-e 1 (- z
))
2027 (defun bfloat-expintegral-chi (z)
2028 (let ((mz (mul -
1 z
)))
2032 (bfloat-expintegral-e 1 z
)
2033 (bfloat-expintegral-e 1 mz
)
2035 (mul -
1 ($log z
))))))
2037 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2038 ;; Moved from bessel.lisp 2008-12-11. Consider deleting it.
2040 ;; Exponential integral E1(x). The Cauchy principal value is used for
2042 (defmfun $expint
(x)
2044 (values (slatec:de1
(float x
))))
2046 (list '($expint simp
) x
))))