Use %%PRETTY-FNAME in more quadpack error messages
[maxima.git] / src / expintegral.lisp
blob2b1261cb774b0795e0526ea18c1b9b9e53767870
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;;;
3 ;;; Exponential Integrals
4 ;;;
5 ;;; This file contains the following Maxima User functions:
6 ;;;
7 ;;; $expintegral_e (n,z) - Exponential Integral En(z)
8 ;;; $expintegral_e1 (z) - Exponential Integral E1(z)
9 ;;; $expintegral_ei (z) - Exponential Integral Ei(z)
10 ;;;
11 ;;; $expintegral_li (z) - Logarithmic Integral Li(z)
12 ;;;
13 ;;; $expintegral_si (z) - Exponential Integral Si(z)
14 ;;; $expintegral_ci (z) - Exponential Integral Ci(z)
15 ;;;
16 ;;; $expintegral_shi (z) - Exponential Integral Shi(z)
17 ;;; $expintegral_chi (z) - Exponential Integral Chi(z)
18 ;;;
19 ;;; $expint (x) - Exponential Integral E1(x) (depreciated)
20 ;;;
21 ;;; Global variables for the Maxima User:
22 ;;;
23 ;;; $expintrep - Change the representation of the Exponential Integral to
24 ;;; gamma_incomplete, expintegral_e1, expintegral_ei,
25 ;;; expintegral_li, expintegral_trig, expintegral_hyp
26 ;;;
27 ;;; $expintexpand - Expand the Exponential Integral E[n](z)
28 ;;; for half integral values in terms of Erfc or Erf and
29 ;;; for positive integers in terms of Ei
30 ;;;
31 ;;; The following features are implemented:
32 ;;;
33 ;;; 1. Numerical evaluation for complex Flonum and Bigfloat numbers
34 ;;; using an expansion in a power series or continued fractions.
35 ;;; The numerical support is fully implemented for the E[n](z) function.
36 ;;; All other functions call E[n](z) for numerical evaluation.
37 ;;;
38 ;;; 2. For a negative integer parameter E[n](z) is automatically expanded in
39 ;;; a finite series in terms of powers and the Exponential function.
40 ;;;
41 ;;; 3. When $expintexpand is set to TRUE or ERF E[n](z) expands
42 ;;; a) for n a half integral number in terms of Erfc (TRUE) or Erf (ERF)
43 ;;; b) for n a positive integer number in terms of Ei
44 ;;;
45 ;;; 3. Simplifications for special values: Ev(0), E[0](z), Li(0), Li(1),...
46 ;;;
47 ;;; 4. Derivatives of the Exponential Integrals
48 ;;;
49 ;;; 5. Change the representation of every Exponential Integral through other
50 ;;; Exponential Integrals or the Incomplete Gamma function.
51 ;;;
52 ;;; 6. Mirror symmetry for all functions and reflection symmetry for
53 ;;; the Exponential Inegral Si and Shi are implemented.
54 ;;;
55 ;;; 7. Handling of taylor expansions as argument.
56 ;;;
57 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
58 ;;; This library is free software; you can redistribute it and/or modify it
59 ;;; under the terms of the GNU General Public License as published by the
60 ;;; Free Software Foundation; either version 2 of the License, or (at
61 ;;; your option) any later version.
62 ;;;
63 ;;; This library is distributed in the hope that it will be useful, but
64 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
65 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
66 ;;; Library General Public License for more details.
67 ;;;
68 ;;; You should have received a copy of the GNU General Public License along
69 ;;; with this library; if not, write to the Free Software
70 ;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
71 ;;;
72 ;;; Copyright (C) 2008 Dieter Kaiser
73 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
75 (in-package :maxima)
77 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
78 ;;; Globals to help debugging the code
79 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
81 (defvar *debug-expintegral* nil
82 "When enabled print debug information.")
84 (defvar *debug-expint-maxit* 0
85 "When in debug mode count the maximum of iterations needed by the algorithm.")
87 (defvar *debug-expint-fracmaxit* 0
88 "When in debug mode count the maximum of iterations needed by the algorithm.")
90 (defvar *debug-expint-bfloatmaxit* 0
91 "When in debug mode count the maximum of iterations needed by the algorithm.")
93 (defvar *debug-expint-fracbfloatmaxit* 0
94 "When in debug mode count the maximum of iterations needed by the algorithm.")
96 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
97 ;;; Globals for the Maxima Users
98 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
100 (defvar $expintexpand nil
101 "When not nil we expand for a half integral parameter of the 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)
119 (if errorsw
120 (throw 'errorsw t)
121 (apply #'merror args)))
123 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
125 ;;; Part 1: The implementation of the Exponential Integral En
127 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
129 ;;; Exponential Integral E distributes over bags
131 (defprop %expintegral_e (mlist $matrix mequal) distribute_over)
133 ;;; Exponential Integral E has mirror symmetry,
134 ;;; but not on the real negative axis.
136 (defprop %expintegral_e conjugate-expintegral-e conjugate-function)
138 (defun conjugate-expintegral-e (args)
139 (let ((n (first args))
140 (z (second args)))
141 (cond ((off-negative-real-axisp z)
142 ;; Definitely not on the negative real axis for z. Mirror symmetry.
143 (take '(%expintegral_e)
144 (take '($conjugate) n)
145 (take '($conjugate) z)))
147 ;; On the negative real axis or no information. Unsimplified.
148 (list '($conjugate simp)
149 (take '(%expintegral_e) n z))))))
151 ;;; Differentiation of Exponential Integral E
153 (defprop %expintegral_e
154 ((n z)
155 ;; The derivative wrt the parameter n is expressed in terms of the
156 ;; Regularized Hypergeometric function 2F2 (see functions.wolfram.com)
157 ((mplus)
158 ((mtimes) -1
159 (($hypergeometric_regularized)
160 ((mlist)
161 ((mplus) 1 ((mtimes) -1 n))
162 ((mplus) 1 ((mtimes) -1 n)))
163 ((mlist)
164 ((mplus) 2 ((mtimes) -1 n))
165 ((mplus) 2 ((mtimes) -1 n)))
166 ((mtimes) -1 z))
167 ((mexpt)
168 ((%gamma) ((mplus) 1 ((mtimes) -1 n))) 2))
169 ((mtimes)
170 ((%gamma) ((mplus) 1 ((mtimes) -1 n)))
171 ((mexpt) z ((mplus) -1 n))
172 ((mplus)
173 ((mtimes) -1
174 ((mqapply)
175 (($psi array) 0)
176 ((mplus) 1 ((mtimes) -1 n))))
177 ((%log) z))))
179 ;; The derivative wrt the argument of the function
180 ((mtimes) -1 ((%expintegral_e) ((mplus) -1 n) z)))
181 grad)
183 ;;; Integral of Exponential Integral E
185 (defprop %expintegral_e
186 ((n z)
188 ((mtimes) -1 ((%expintegral_e) ((mplus) 1 n) z)))
189 integral)
191 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
193 ;;; We support a simplim%function. The function is looked up in simplimit and
194 ;;; handles specific values of the function.
196 (defprop %expintegral_e simplim%expintegral_e simplim%function)
198 (defun simplim%expintegral_e (expr var val)
199 ;; Look for the limit of the arguments.
200 (let ((a (limit (cadr expr) var val 'think))
201 (z (limit (caddr expr) var val 'think)))
202 (cond ((and (onep1 a)
203 (or (eq z '$zeroa)
204 (eq z '$zerob)
205 (zerop1 z)))
206 ;; Special case order a=1
207 '$inf)
209 ((member ($sign (add ($realpart a) -1)) '($neg $nz $zero))
210 ; realpart of order < 1
211 (cond ((eq z '$zeroa)
212 ;; from above, always inf
213 '$inf)
214 ((eq z '$zerob)
215 ;; this can be further improved to give a directed infinity
216 '$infinity)
217 ((zerop1 z)
218 ;; no direction, return infinity
219 '$infinity)
221 (ftake '%expintegral_e a z))))
223 ;; All other cases are handled by the simplifier of the function.
224 (ftake '%expintegral_e a z)))))
226 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
228 ;;; Exponential Integral E is a simplifying function
229 (def-simplifier expintegral_e (order arg)
230 (let ((ratorder))
231 (cond
232 ;; Check for special values
233 ((or (eq arg '$inf)
234 (alike1 arg '((mtimes) -1 $minf)))
235 ;; arg is inf or -minf, return zero
238 ((zerop1 arg)
239 (let ((sgn ($sign (add ($realpart order) -1))))
240 (cond
241 ((eq sgn '$pos)
242 ;; we handle the special case E[v](0) = 1/(v-1), for realpart(v)>1
243 (inv (add order -1)))
244 ((member sgn '($neg $nz $zero))
245 (simp-domain-error
246 (intl:gettext
247 "expintegral_e: expintegral_e(~:M,~:M) is undefined.")
248 order arg))
249 (t (give-up)))))
251 ((or (and (symbolp order) (member order *infinities*))
252 (and (symbolp arg) (member arg *infinities*)))
253 ;; order or arg is one of the infinities, we return a noun form,
254 ;; but we have already handled the special value inf for arg.
255 (give-up))
257 ((and (numberp order) (integerp order))
258 ;; The parameter of the Exponential integral is an integer. For this
259 ;; case we can do further simplifications or numerical evaluation.
260 (cond
261 ((= order 0)
262 ;; Special case E[0](z) = %e^(-z)/z, z<>0
263 ;; The case z=0 is already handled.
264 (div (power '$%e (mul -1 arg)) arg))
266 ((= order -1)
267 ;; Special case E[-1](0) = ((z+1)*%e^(-z))/z^2, z<>0
268 ;; The case z=0 is already handled.
269 (div (mul (power '$%e (mul -1 arg)) (add arg 1)) (mul arg arg)))
271 ((< order -1)
272 ;; We expand in a series, z<>0
273 (mul
274 (factorial (- order))
275 (power arg (+ order -1))
276 (power '$%e (mul -1 arg))
277 (let ((index (gensumindex)))
278 (dosum
279 (div (power arg index)
280 (take '(mfactorial) index))
281 index 0 (- order) t))))
283 ((and (> order 0)
284 (complex-float-numerical-eval-p arg))
285 ;; Numerical evaluation for double float real or complex arg
286 ;; order is an integer > 0 and arg <> 0 for order < 2
287 (let ((carg (complex ($float ($realpart arg))
288 ($float ($imagpart arg)))))
289 (complexify (expintegral-e order carg))))
291 ((and (> order 0)
292 (complex-bigfloat-numerical-eval-p arg))
293 ;; Numerical evaluation for Bigfloat real or complex arg.
294 (let* (($ratprint nil)
295 (carg (add ($bfloat ($realpart arg))
296 (mul '$%i ($bfloat ($imagpart arg)))))
297 (result (bfloat-expintegral-e order carg)))
298 (add ($realpart result) (mul '$%i ($imagpart result)))))
300 ((and $expintexpand (> order 0))
301 ;; We only expand in terms of the Exponential Integral Ei
302 ;; if the expand flag is set.
303 (sub (mul -1
304 (power (mul -1 arg) (- order 1))
305 (inv (factorial (- order 1)))
306 (add (take '(%expintegral_ei) (mul -1 arg))
307 (mul (inv 2)
308 (sub (take '(%log) (mul -1 (inv arg)))
309 (take '(%log) (mul -1 arg))))
310 (take '(%log) arg)))
311 (mul (power '$%e (mul -1 arg))
312 (let ((index (gensumindex)))
313 (dosum
314 (div (power arg (add index -1))
315 (take '($pochhammer) (- 1 order) index))
316 index 1 (- order 1) t)))))
318 ((eq $expintrep '%gamma_incomplete)
319 ;; We transform to the Incomplete Gamma function.
320 (mul (power arg (- order 1))
321 (take '(%gamma_incomplete) (- 1 order) arg)))
324 (give-up))))
326 ((complex-float-numerical-eval-p order arg)
327 (let (z)
328 (cond
329 ((and (setq z (integer-representation-p order))
330 (plusp z))
331 ;; We have a pure real positive order and the realpart is a float
332 ;; representation of an integer value.
333 ;; We call the routine for an integer order.
334 (let ((carg (complex ($float ($realpart arg))
335 ($float ($imagpart arg)))))
336 (complexify (expintegral-e z carg))))
338 ;; The general case, order and arg are complex or real.
339 (let ((corder (complex ($float ($realpart order))
340 ($float ($imagpart order))))
341 (carg (complex ($float ($realpart arg))
342 ($float ($imagpart arg)))))
343 (complexify (frac-expintegral-e corder carg)))))))
345 ((complex-bigfloat-numerical-eval-p order arg)
346 (let (z)
347 (cond
348 ((and (setq z (integer-representation-p order))
349 (plusp z))
350 ;; We have a real positive order and the realpart is a Float or
351 ;; Bigfloat representation of an integer value.
352 ;; We call the routine for an integer order.
353 (let* (($ratprint nil)
354 (carg (add ($bfloat ($realpart arg))
355 (mul '$%i ($bfloat ($imagpart arg)))))
356 (result (bfloat-expintegral-e z carg)))
357 (add ($realpart result)
358 (mul '$%i ($imagpart result)))))
360 ;; the general case, order and arg are bigfloat or complex bigfloat
361 (let* (($ratprint nil)
362 (corder (add ($bfloat ($realpart order))
363 (mul '$%i ($bfloat ($imagpart order)))))
364 (carg (add ($bfloat ($realpart arg))
365 (mul '$%i ($bfloat ($imagpart arg)))))
366 (result (frac-bfloat-expintegral-e corder carg)))
367 (add ($realpart result)
368 (mul '$%i ($imagpart result))))))))
370 ((and $expintexpand
371 (setq ratorder (max-numeric-ratio-p order 2)))
372 ;; We have a half integral order and $expintexpand is not NIL.
373 ;; We expand in a series in terms of the Erfc or Erf function.
374 (let ((func (cond ((eq $expintexpand '%erf)
375 (sub 1 ($erf (power arg '((rat simp) 1 2)))))
377 ($erfc (power arg '((rat simp) 1 2)))))))
378 (cond
379 ((= ratorder 1/2)
380 (mul (power '$%pi '((rat simp) 1 2))
381 (power arg '((rat simp) -1 2))
382 func))
383 ((= ratorder -1/2)
384 (add
385 (mul
386 (power '$%pi '((rat simp) 1 2))
387 (inv (mul 2 (power arg '((rat simp) 3 2))))
388 func)
389 (div (power '$%e (mul -1 arg)) arg)))
391 (let ((n (- ratorder 1/2)))
392 (mul
393 (power arg (sub n '((rat simp) 1 2)))
394 (add
395 (mul func (take '(%gamma) (sub '((rat simp) 1 2) n)))
396 (mul
397 (power '$%e (mul -1 arg))
398 (let ((index (gensumindex)))
399 (dosum
400 (div
401 (power arg (add index '((rat simp) 1 2)))
402 (take '($pochhammer)
403 (sub '((rat simp) 1 2) n)
404 (add index n 1)))
405 index 0 (mul -1 (add n 1)) t)))
406 (mul -1
407 (power '$%e (mul -1 arg))
408 (let ((index (gensumindex)))
409 (dosum
410 (div
411 (power arg (add index '((rat simp) 1 2)))
412 (take '($pochhammer)
413 (sub '((rat simp) 1 2) n)
414 (add index n 1)))
415 index (- n) -1 t))))))))))
417 ((eq $expintrep '%gamma_incomplete)
418 ;; We transform to the Incomplete Gamma function.
419 (mul (power arg (sub order 1))
420 (take '(%gamma_incomplete) (sub 1 order) arg)))
421 ($hypergeometric_representation
422 ;; See http://functions.wolfram.com/06.34.26.0002.01:
424 ;; expintegral_e(v,z) = z^(v-1)*gamma(1-v)
425 ;; - hypergeometric([1-v],[2-v], -z)
427 ;; But hypergeometric([1-v],[2-v],-z) gets simplified to
428 ;; hypergeometric([1],[2-v],z)*exp(-z)
429 (sub (mul (power arg (sub order 1))
430 (ftake '%gamma (sub 1 order)))
431 (div (ftake '%hypergeometric
432 (make-mlist (sub 1 order))
433 (make-mlist (sub 2 order))
434 (neg arg))
435 (sub 1 order))))
437 (give-up)))))
439 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
440 ;;; Numerical evaluation of the Exponential Integral En(z)
442 ;;; The following numerical routines are implemented:
444 ;;; expintegral-e - n positive integer, z real or complex
445 ;;; frac-expintegral-e - n,z real or complex; n not a positive integer
446 ;;; bfloat-expintegral-e - n positive integer,
447 ;;; z Bigfloat or Complex Bigfloat
448 ;;; frac-bfloat-expintegral-e - n Bigfloat, z Bigfloat or Complex Bigfloat
450 ;;; The algorithm are implemented for full support of Flonum and Bigfloat real
451 ;;; or Complex parameter and argument of the Exponential Integral.
452 ;;; Because we have no support for Complex Bigfloat arguments of the Gamma
453 ;;; function the evaluation for a Complex Bigfloat parameter don't give
454 ;;; the desiered accuracy.
456 ;;; The flonum versions return a CL complex number. The Bigfloat versions
457 ;;; a Maxima Complex Bigfloat number. It is assumed that the calling routine
458 ;;; check the values. We don't handle any special case. This has to be done by
459 ;;; the calling routine.
461 ;;; The evaluation uses an expansion in continued fractions for arguments with
462 ;;; realpart(z) > 0 and abs(z)> 1.0 (A&S 5.1.22). This expansion works for
463 ;;; every Real or Complex numbers including Bigfloat numbers for the parameter n
464 ;;; and the argument z:
466 ;;; 1 n 1 n+1 2
467 ;;; En(z) = e^(-z) * ( --- --- --- --- --- ... )
468 ;;; z+ 1+ z+ 1+ z+
470 ;;; The continued fraction is evaluated by the modified Lentz's method
471 ;;; for the more rapidly converging even form.
473 ;;; For the parameter n an positive integer we do an expansion in a power series
474 ;;; (A&S 5.1.12):
475 ;;; inf
476 ;;; ===
477 ;;; (-z)^(n-1) \ (-z)^m
478 ;;; En(z) = --------- * (-log(z)+psi(n)) * > ---------- ; n an integer
479 ;;; (n-1)! / (m-n+1)*m!
480 ;;; ===
481 ;;; m=0 (m <> n-1)
483 ;;; For an parameter n not an integer we expand in the following series
484 ;;; (functions.wolfram.com ):
485 ;;; inf
486 ;;; ===
487 ;;; \ (-1)^m * z^m
488 ;;; Ev(z) = gamma(1-v) * z^(v-1) * > ------------- ; n not an integer
489 ;;; / (m-v+1)*m!
490 ;;; ===
491 ;;; m=0
493 ;;; The evaluation stops if an accuracy better than *expint-eps* is achieved.
494 ;;; If the expansion does not converge within *expint-maxit* steps a Maxima
495 ;;; Error is thrown.
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))
532 (cond
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.~%"))
541 (let* ((b (+ z n))
542 (c (/ 1.0 (* *expint-eps* *expint-eps*)))
543 (d (/ 1.0 b))
544 (n1 (- n 1))
545 (h d)
546 (e 0.0))
547 (do* ((i 1 (+ i 1))
548 (a (* -1 n) (* (- i) (+ n1 i))))
549 ((> i *expint-maxit*)
550 (merror
551 (intl:gettext "expintegral_e: continued fractions failed.")))
553 (setq b (+ b 2.0))
554 (setq d (/ 1.0 (+ (* a d) b)))
555 (setq c (+ b (/ a c)))
556 (setq e (* c d))
557 (setq h (* h e))
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.~%"))
567 (let* ((n1 (- n 1))
568 (euler (mget '$%gamma '$numer))
569 (r (if (= n1 0) (- (- euler) (log z)) (/ 1.0 n1)))
570 (f 1.0)
571 (e 0.0))
572 (do ((i 1 (+ i 1)))
573 ((> i *expint-maxit*)
574 (merror (intl:gettext "expintegral_e: series failed.")))
575 (setq f (* -1 f (/ z i)))
576 (cond
577 ((= i n1)
578 (let ((psi (- euler)))
579 (dotimes (ii n1)
580 (setq psi (+ psi (/ 1.0 (+ ii 1)))))
581 (setq e (* f (- psi (log z))))))
583 (setq e (/ (- f) (- i n1)))))
584 (setq r (+ r e))
585 (when (< (abs e) (* (abs r) *expint-eps*))
586 (when *debug-expintegral*
587 (setq *debug-expint-maxit* (max *debug-expint-maxit* i)))
588 (return r))))))))
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))
606 (cond
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.~%"))
611 (let* ((b (+ z n))
612 (c (/ 1.0 (* *expint-eps* *expint-eps*)))
613 (d (/ 1.0 b))
614 (n1 (- n 1))
615 (h d)
616 (e 0.0))
617 (do* ((i 1 (+ i 1))
618 (a (* -1 n) (* (- i) (+ n1 i))))
619 ((> i *expint-maxit*)
620 (merror
621 (intl:gettext "expintegral_e: continued fractions failed.")))
623 (setq b (+ b 2.0))
624 (setq d (/ 1.0 (+ (* a d) b)))
625 (setq c (+ b (/ a c)))
626 (setq e (* c d))
627 (setq h (* h e))
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)
635 (> (realpart 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.~%"))
648 (let* ((n1 (- n 1))
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))))
655 (f 1.0)
656 (e 0.0))
657 (do ((i 1 (+ i 1)))
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)))
662 (setq r (+ r e))
663 (when (< (abs e) (* (abs r) *expint-eps*))
664 (when *debug-expintegral*
665 (setq *debug-expint-fracmaxit* (max *debug-expint-fracmaxit* i)))
666 (return r))))))))
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
683 ;;; in the code.
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))
703 (cond
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.~%"))
710 (let* ((b (add z n))
711 (c (div bigfloatone (mul *expint-eps* *expint-eps*)))
712 (d (cdiv bigfloatone b))
713 (n1 (- n 1))
714 (h d)
715 (e 0.0))
716 (do* ((i 1 (+ i 1))
717 (a (* -1 n) (* (- i) (+ n1 i))))
718 ((> i *expint-maxit*)
719 (merror
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)))
725 (setq e (cmul c d))
726 (setq h (cmul h e))
728 (when (eq ($sign (sub (cabs (sub e bigfloatone)) *expint-eps*))
729 '$neg)
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.~%"))
738 (let* ((n1 (- n 1))
739 (meuler (mul -1 bigfloat%gamma))
740 (r (if (= n1 0) (sub meuler ($log z)) (div bigfloatone n1)))
741 (f bigfloatone)
742 (e bigfloatzero))
743 (do* ((i 1 (+ i 1)))
744 ((> i *expint-maxit*)
745 (merror (intl:gettext "expintegral_e: series failed.")))
746 (setq f (mul -1 (cmul f (cdiv z i))))
747 (cond
748 ((= i n1)
749 (let ((psi meuler))
750 (dotimes (ii n1)
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)))))
755 (setq r (add r e))
756 (when (eq ($sign (sub (cabs e) (cmul (cabs r) *expint-eps*)))
757 '$neg)
758 (when *debug-expintegral*
759 (setq *debug-expint-bfloatmaxit*
760 (max *debug-expint-bfloatmaxit* i)))
761 (return r))))))))
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))
782 (cond
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.~%"))
789 (let* ((b (add z n))
790 (c (div bigfloatone (mul *expint-eps* *expint-eps*)))
791 (d (cdiv bigfloatone b))
792 (n1 (sub n 1))
793 (h d)
794 (e 0.0))
795 (do* ((i 1 (+ i 1))
796 (a (mul -1 n) (cmul (- i) (add n1 i))))
797 ((> i *expint-maxit*)
798 (merror
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)))
804 (setq e (cmul c d))
805 (setq h (cmul h e))
807 (when (eq ($sign (sub (cabs (sub e bigfloatone)) *expint-eps*))
808 '$neg)
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)
815 (= ($imagpart n) 0)
816 (> ($realpart n) 0)
817 (= (nth-value 1 (truncate ($realpart n))) 0))
818 (and ($bfloatp n)
819 (eq ($sign n) '$pos)
820 (equal (sub (mul 2 ($fix n)) (mul 2 n))
821 bigfloatzero)))
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)))
837 (f bigfloatone)
838 (e bigfloatzero))
839 (do ((i 1 (+ i 1)))
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)))
844 (setq r (add r e))
845 (when (eq ($sign (sub (cabs e) (cmul (cabs r) *expint-eps*)))
846 '$neg)
847 (when *debug-expintegral*
848 (setq *debug-expint-fracbfloatmaxit*
849 (max *debug-expint-fracbfloatmaxit* i)))
850 (return r))))))))
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
879 ((x)
880 ((mtimes) -1
881 ((mexpt) x -1)
882 ((mexpt) $%e ((mtimes) -1 x))))
883 grad)
885 ;;; Integral of Exponential Integral E1
887 (defprop %expintegral_e1
888 ((z)
889 ((mtimes) -1 ((%expintegral_e) 2 z)))
890 integral)
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)))
902 (cond
903 ;; Handle an argument 0 at this place
904 ((or (zerop1 z)
905 (eq z '$zeroa)
906 (eq z '$zerob))
907 ;; limit is inf from both sides
908 '$inf)
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)
917 (cond
918 ;; Check for special values
919 ((or (eq arg '$inf)
920 (alike1 arg '((mtimes) -1 $minf)))
922 ((zerop1 arg)
923 (simp-domain-error
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)))
944 ((and $expintrep
945 (member $expintrep *expintflag* :test #'eq)
946 (not (eq $expintrep '%expintegral_e1)))
947 (case $expintrep
948 (%gamma_incomplete
949 (take '(%gamma_incomplete) 0 arg))
950 (%expintegral_ei
951 (add (mul -1 (take '(%expintegral_ei) (mul -1 arg)))
952 (mul (inv 2)
953 (sub (take '(%log) (mul -1 arg))
954 (take '(%log) (mul -1 (inv arg)))))
955 (mul -1 (take '(%log) arg))))
956 (%expintegral_li
957 (add (mul -1 (take '(%expintegral_li) (power '$%e (mul -1 arg))))
958 (mul -1 (take '(%log) arg))
959 (mul (inv 2)
960 (sub (take '(%log) (mul -1 arg))
961 (take '(%log) (mul -1 (inv arg)))))))
962 ($expintegral_trig
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))))
967 ($expintegral_hyp
968 (sub (take '(%expintegral_shi) arg)
969 (take '(%expintegral_chi) arg)))
971 (give-up))))
974 (give-up))))
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
993 ((x)
994 ((mtimes) ((mexpt) x -1) ((mexpt) $%e x)))
995 grad)
997 ;;; Integral of Exponential Ei
999 (defprop %expintegral_ei
1000 ((x)
1001 ((mplus)
1002 ((mtimes) -1 ((mexpt) $%e x))
1003 ((mtimes) x ((%expintegral_ei) x))))
1004 integral)
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)))
1016 (cond
1017 ;; Handle an argument 0 at this place
1018 ((or (zerop1 z)
1019 (eq z '$zeroa)
1020 (eq z '$zerob))
1021 '$minf)
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)
1030 (cond
1031 ;; Check special values
1032 ((zerop1 arg)
1033 (simp-domain-error
1034 (intl:gettext "expintegral_ei: expintegral_ei(~:M) is undefined.")
1035 arg))
1036 ((or (eq arg '$inf)
1037 (alike1 arg '((mtimes) -1 $minf)))
1038 '$inf)
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)))
1044 (mul '$%i '$%pi))
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)))
1065 ((and $expintrep
1066 (member $expintrep *expintflag*)
1067 (not (eq $expintrep '%expintegral_ei)))
1068 (case $expintrep
1069 (%gamma_incomplete
1070 (add (mul -1 (take '(%gamma_incomplete) 0 (mul -1 arg)))
1071 (mul (inv 2)
1072 (sub (take '(%log) arg)
1073 (take '(%log) (inv arg))))
1074 (mul -1 (take '(%log) (mul -1 arg)))))
1075 (%expintegral_e1
1076 (add (mul -1 (take '(%expintegral_e1) (mul -1 arg)))
1077 (mul (inv 2)
1078 (sub (take '(%log) arg)
1079 (take '(%log) (inv arg))))
1080 (mul -1 (take '(%log) (mul -1 arg)))))
1081 (%expintegral_li
1082 (take '(%expintegral_li) (power '$%e arg)))
1083 ($expintegral_trig
1084 (add (take '(%expintegral_ci) (mul '$%i arg))
1085 (mul -1 '$%i (take '(%expintegral_si) (mul '$%i arg)))
1086 (mul (inv -2)
1087 (sub (take '(%log) (inv arg))
1088 (take '(%log) arg)))
1089 (mul -1 (take '(%log) (mul '$%i arg)))))
1090 ($expintegral_hyp
1091 (add (take '(%expintegral_chi) arg)
1092 (take '(%expintegral_shi) arg)
1093 (mul (inv -2)
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).
1107 (add (mul arg
1108 (ftake '%hypergeometric
1109 (make-mlist 1 1)
1110 (make-mlist 2 2)
1111 arg))
1112 (mul 1//2
1113 (sub (ftake '%log arg)
1114 (ftake '%log (div 1 arg))))
1115 '$%gamma))
1117 (give-up))))
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.)
1135 (cond
1136 ((> (imagpart z) 0)
1137 ;; Positive imaginary part. Add phase %i*%pi.
1138 (complex 0 (float pi)))
1139 ((< (imagpart z) 0)
1140 ;; Negative imaginary part. Add phase -%i*%pi.
1141 (complex 0 (- (float pi))))
1142 ((> (realpart z) 0)
1143 ;; Positive real value. Add phase -%i*pi.
1144 (complex 0 (- (float pi))))
1145 ;; Negative real value. No phase factor.
1146 (t 0))))
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
1153 ;;; calculation.
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
1192 ((x)
1193 ((mtimes) ((mexpt) ((%log) x) -1)))
1194 grad)
1196 ;;; Integral of Exponential Li
1198 (defprop %expintegral_li
1199 ((x)
1200 ((mplus)
1201 ((mtimes) x ((%expintegral_li) x))
1202 ((mtimes) -1 ((%expintegral_ei) ((mtimes) 2 ((%log) x))))))
1203 integral)
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)))
1215 (cond
1216 ;; Handle an argument 1 at this place
1217 ((onep1 z) '$minf)
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)
1226 (cond
1227 ((zerop1 arg) arg)
1228 ((onep1 arg)
1229 (simp-domain-error
1230 (intl:gettext "expintegral_li: expintegral_li(~:M) is undefined.") arg))
1231 ((or (eq arg '$inf)
1232 (alike1 arg '((mtimes) -1 $minf)))
1233 '$inf)
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)))
1251 ((and $expintrep
1252 (member $expintrep *expintflag*)
1253 (not (eq $expintrep '%expintegral_li)))
1254 (let ((logarg (take '(%log) arg)))
1255 (case $expintrep
1256 (%gamma_incomplete
1257 (add (mul -1 (take '(%gamma_incomplete) 0 (mul -1 logarg)))
1258 (mul (inv 2)
1259 (sub (take '(%log) logarg)
1260 (take '(%log) (inv logarg))))
1261 (mul -1 (take '(%log) (mul -1 logarg)))))
1262 (%expintegral_e1
1263 (add (mul -1 (take '(%expintegral_e1) (mul -1 logarg)))
1264 (mul (inv 2)
1265 (sub (take '(%log) logarg)
1266 (take '(%log) (inv logarg))))
1267 (mul -1 (take '(%log) (mul -1 logarg)))))
1268 (%expintegral_ei
1269 (take '(%expintegral_ei) logarg))
1270 ($expintegral_trig
1271 (add (take '(%expintegral_ci) (mul '$%i logarg))
1272 (mul -1 '$%i (take '(%expintegral_si) (mul '$%i logarg)))
1273 (mul (inv -2)
1274 (sub (take '(%log) (inv logarg))
1275 (take '(%log) logarg)))
1276 (mul -1 (take '(%log) (mul '$%i logarg)))))
1277 ($expintegral_hyp
1278 (add (take '(%expintegral_chi) logarg)
1279 (take '(%expintegral_shi) logarg)
1280 (mul (inv -2)
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
1295 (make-mlist 1 1)
1296 (make-mlist 2 2)
1297 (ftake '%log arg)))
1298 (mul 1//2
1299 (sub (ftake '%log (ftake '%log arg))
1300 (ftake '%log (div 1 (ftake '%log arg)))))
1301 '$%gamma))
1303 (give-up))))
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
1340 ((x)
1341 ((mtimes) ((%sin) x) ((mexpt) x -1)))
1342 grad)
1344 ;;; Integral of Exponential Si
1346 (defprop %expintegral_si
1347 ((x)
1348 ((mplus)
1349 ((%cos) x)
1350 ((mtimes) x ((%expintegral_si) x))))
1351 integral)
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)
1369 (cond
1370 ;; Check for special values
1371 ((zerop1 arg) arg)
1372 ((or (eq arg '$inf)
1373 (alike1 arg '((mtimes) -1 $minf)))
1374 (div '$%pi 2))
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))
1396 ((and $expintrep
1397 (member $expintrep *expintflag*)
1398 (not (eq $expintrep '$expintegral_trig)))
1399 (case $expintrep
1400 (%gamma_incomplete
1401 (mul (div '$%i 2)
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))))))
1406 (%expintegral_e1
1407 (mul (div '$%i 2)
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))))))
1412 (%expintegral_ei
1413 (mul (div '$%i 4)
1414 (add (mul 2
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)))))
1421 (%expintegral_li
1422 (mul (inv (mul 2 '$%i))
1423 (add (take '(%expintegral_li) (power '$%e (mul '$%i arg)))
1424 (mul -1
1425 (take '(%expintegral_li)
1426 (power '$%e (mul -1 '$%e arg))))
1427 (mul (div '$%pi -2)
1428 (take '(%signum) ($realpart arg))))))
1429 ($expintegral_hyp
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)
1437 (mul arg
1438 (ftake '%hypergeometric
1439 (make-mlist 1//2)
1440 (make-mlist 3//2 3//2)
1441 (div (mul arg arg)
1442 -4))))
1444 (give-up))))
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))))
1460 (* (complex 0 0.5)
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)))
1469 (cmul
1470 (mul 0.5 '$%i)
1471 (add
1472 (bfloat-expintegral-e 1 mz*%i)
1473 (mul -1 (bfloat-expintegral-e 1 z*%i))
1474 ($log mz*%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
1498 ((x)
1499 ((mtimes) ((%sinh) x) ((mexpt) x -1)))
1500 grad)
1502 ;;; Integral of Exponential Shi
1504 (defprop %expintegral_shi
1505 ((x)
1506 ((mplus)
1507 ((mtimes) -1 ((%cosh) x))
1508 ((mtimes) x ((%expintegral_shi) x))))
1509 integral)
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)))
1521 (cond
1522 ;; Handle infinities at this place
1523 ((eq z '$inf)
1524 '$inf)
1525 ((eq z '$minf)
1526 '$minf)
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)
1535 (cond
1536 ;; Check for special values
1537 ((zerop1 arg) arg)
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))
1565 ((and $expintrep
1566 (member $expintrep *expintflag*)
1567 (not (eq $expintrep '$expintegral_hyp)))
1568 (case $expintrep
1569 (%gamma_incomplete
1570 (mul (inv 2)
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))))
1575 (%expintegral_e1
1576 (mul (inv 2)
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))))
1581 (%expintegral_ei
1582 (mul (inv 4)
1583 (add (mul 2
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)))))
1590 (%expintegral_li
1591 (add (mul (inv 2)
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)))))
1596 ($expintegral_trig
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)
1604 (mul arg
1605 (ftake '%hypergeometric
1606 (make-mlist 1//2)
1607 (make-mlist 3//2 3//2)
1608 (div (mul arg arg)
1609 4))))
1611 (give-up))))
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)
1626 (expintegral-e 1 z)
1627 (- (expintegral-e 1 (- z)))
1628 (- (log (- z)))
1629 (log z))))
1631 (defun bfloat-expintegral-shi (z)
1632 (let ((mz (mul -1 z)))
1633 (mul
1635 (add
1636 (bfloat-expintegral-e 1 z)
1637 (mul -1 (bfloat-expintegral-e 1 mz))
1638 (mul -1 ($log mz))
1639 ($log z)))))
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
1668 ((x)
1669 ((mtimes) ((%cos) x) ((mexpt) x -1)))
1670 grad)
1672 ;;; Integral of Exponential Ci
1674 (defprop %expintegral_ci
1675 ((x)
1676 ((mplus)
1677 ((mtimes) x ((%expintegral_ci) x))
1678 ((mtimes) -1 ((%sin) x))))
1679 integral)
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)))
1691 (cond
1692 ;; Handle an argument 0 at this place
1693 ((or (zerop1 z)
1694 (eq z '$zeroa)
1695 (eq z '$zerob))
1696 '$minf)
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)
1705 (cond
1706 ;; Check for special values
1707 ((zerop1 arg)
1708 (simp-domain-error
1709 (intl:gettext "expintegral_ci: expintegral_ci(~:M) is undefined.") arg))
1710 ((or (eq arg '$inf)
1711 (alike1 arg '((mtimes) -1 $minf)))
1713 ((or (eq arg '$minf)
1714 (alike1 arg '((mtimes) -1 $inf)))
1715 (mul '$%i '$%pi))
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)))
1733 ((and $expintrep
1734 (member $expintrep *expintflag*)
1735 (not (eq $expintrep '$expintegral_trig)))
1736 (case $expintrep
1737 (%gamma_incomplete
1738 (sub (take '(%log) arg)
1739 (mul (inv 2)
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))))))
1744 (%expintegral_e1
1745 (add (mul (inv -2)
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)))
1751 (%expintegral_ei
1752 (add (mul (inv 4)
1753 (add (mul 2
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)))
1761 (%expintegral_li
1762 (add (mul (inv 2)
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)))))
1770 ($expintegral_hyp
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
1781 (add
1782 (mul (div (mul arg arg) -4)
1783 (ftake '%hypergeometric
1784 (make-mlist 1 1)
1785 (make-mlist 2 2 3//2)
1786 (div (mul arg arg)
1787 -4)))
1788 (ftake '%log arg)
1789 '$%gamma))
1791 (give-up))))
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))))
1804 (+ (* -0.5
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))))
1809 (log z))))
1811 (defun bfloat-expintegral-ci (z)
1812 (let ((z*%i (cmul '$%i z))
1813 (mz*%i (cmul (mul -1 '$%i) z)))
1814 (add
1815 (cmul
1816 -0.5
1817 (add
1818 (bfloat-expintegral-e 1 mz*%i)
1819 (bfloat-expintegral-e 1 z*%i)
1820 ($log mz*%i)
1821 ($log z*%i)))
1822 ($log z))))
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
1851 ((x)
1852 ((mtimes) ((%cosh) x) ((mexpt) x -1)))
1853 grad)
1855 ;;; Integral of Exponential Chi
1857 (defprop %expintegral_chi
1858 ((x)
1859 ((mplus)
1860 ((mtimes) x ((%expintegral_chi) x))
1861 ((mtimes) -1 ((%sinh) x))))
1862 integral)
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)))
1874 (cond
1875 ;; Handle an argument 0 at this place
1876 ((or (zerop1 z)
1877 (eq z '$zeroa)
1878 (eq z '$zerob))
1879 '$minf)
1880 ((or (eq z '$inf)
1881 (eq z '$minf))
1882 '$inf)
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)
1891 (cond
1892 ;; Check for special values
1893 ((zerop1 arg)
1894 ;; First check for zero argument. Throw Maxima error.
1895 (simp-domain-error
1896 (intl:gettext "expintegral_chi: expintegral_chi(~:M) is undefined.")
1897 arg))
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)))
1921 ((and $expintrep
1922 (member $expintrep *expintflag*)
1923 (not (eq $expintrep '$expintegral_hyp)))
1924 (case $expintrep
1925 (%gamma_incomplete
1926 (mul (inv -2)
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)))))
1931 (%expintegral_e1
1932 (mul (inv -2)
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)))))
1937 (%expintegral_ei
1938 (mul (inv 4)
1939 (add (mul 2
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)))))
1946 (%expintegral_li
1947 (add (mul (inv 2)
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)))
1952 (mul (inv 2)
1953 (add (take '(%log) (inv arg))
1954 (take '(%log) arg)))))
1955 ($expintegral_trig
1956 (add (take '(%expintegral_ci) (mul '$%i arg))
1957 (take '(%log) 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
1966 (add
1967 (mul (div (mul arg arg) 4)
1968 (ftake '%hypergeometric
1969 (make-mlist 1 1)
1970 (make-mlist 2 2 3//2)
1971 (div (mul arg arg)
1972 4)))
1973 (ftake '%log arg)
1974 '$%gamma))
1976 (give-up))))
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)
1989 -0.5
1991 (expintegral-e 1 z)
1992 (expintegral-e 1 (- z))
1993 (log (- z))
1994 (- (log z)))))
1996 (defun bfloat-expintegral-chi (z)
1997 (let ((mz (mul -1 z)))
1998 (mul
1999 -0.5
2000 (add
2001 (bfloat-expintegral-e 1 z)
2002 (bfloat-expintegral-e 1 mz)
2003 ($log 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
2010 ;; negative x.
2011 (defmfun $expint (x)
2012 (cond ((numberp x)
2013 (values (slatec:de1 (float x))))
2015 (list '($expint simp) x))))