Support RETURN-FROM in DEF%TR forms
[maxima.git] / src / expintegral.lisp
blob824d6662c6b6922f32172853d598699d134f6048
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 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)
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 (cond
328 ((and (setq z (integer-representation-p order))
329 (plusp z))
330 ;; We have a pure real positive order and the realpart is a float
331 ;; representation of an integer value.
332 ;; We call the routine for an integer order.
333 (let ((carg (complex ($float ($realpart arg))
334 ($float ($imagpart arg)))))
335 (complexify (expintegral-e z carg))))
337 ;; The general case, order and arg are complex or real.
338 (let ((corder (complex ($float ($realpart order))
339 ($float ($imagpart order))))
340 (carg (complex ($float ($realpart arg))
341 ($float ($imagpart arg)))))
342 (complexify (frac-expintegral-e corder carg))))))
344 ((complex-bigfloat-numerical-eval-p order arg)
345 (cond
346 ((and (setq z (integer-representation-p order))
347 (plusp z))
348 ;; We have a real positive order and the realpart is a Float or
349 ;; Bigfloat representation of an integer value.
350 ;; We call the routine for an integer order.
351 (let* (($ratprint nil)
352 (carg (add ($bfloat ($realpart arg))
353 (mul '$%i ($bfloat ($imagpart arg)))))
354 (result (bfloat-expintegral-e z carg)))
355 (add ($realpart result)
356 (mul '$%i ($imagpart result)))))
358 ;; the general case, order and arg are bigfloat or complex bigfloat
359 (let* (($ratprint nil)
360 (corder (add ($bfloat ($realpart order))
361 (mul '$%i ($bfloat ($imagpart order)))))
362 (carg (add ($bfloat ($realpart arg))
363 (mul '$%i ($bfloat ($imagpart arg)))))
364 (result (frac-bfloat-expintegral-e corder carg)))
365 (add ($realpart result)
366 (mul '$%i ($imagpart result)))))))
368 ((and $expintexpand
369 (setq ratorder (max-numeric-ratio-p order 2)))
370 ;; We have a half integral order and $expintexpand is not NIL.
371 ;; We expand in a series in terms of the Erfc or Erf function.
372 (let ((func (cond ((eq $expintexpand '%erf)
373 (sub 1 ($erf (power arg '((rat simp) 1 2)))))
375 ($erfc (power arg '((rat simp) 1 2)))))))
376 (cond
377 ((= ratorder 1/2)
378 (mul (power '$%pi '((rat simp) 1 2))
379 (power arg '((rat simp) -1 2))
380 func))
381 ((= ratorder -1/2)
382 (add
383 (mul
384 (power '$%pi '((rat simp) 1 2))
385 (inv (mul 2 (power arg '((rat simp) 3 2))))
386 func)
387 (div (power '$%e (mul -1 arg)) arg)))
389 (let ((n (- ratorder 1/2)))
390 (mul
391 (power arg (sub n '((rat simp) 1 2)))
392 (add
393 (mul func (take '(%gamma) (sub '((rat simp) 1 2) n)))
394 (mul
395 (power '$%e (mul -1 arg))
396 (let ((index (gensumindex)))
397 (dosum
398 (div
399 (power arg (add index '((rat simp) 1 2)))
400 (take '($pochhammer)
401 (sub '((rat simp) 1 2) n)
402 (add index n 1)))
403 index 0 (mul -1 (add n 1)) t)))
404 (mul -1
405 (power '$%e (mul -1 arg))
406 (let ((index (gensumindex)))
407 (dosum
408 (div
409 (power arg (add index '((rat simp) 1 2)))
410 (take '($pochhammer)
411 (sub '((rat simp) 1 2) n)
412 (add index n 1)))
413 index (- n) -1 t))))))))))
415 ((eq $expintrep '%gamma_incomplete)
416 ;; We transform to the Incomplete Gamma function.
417 (mul (power arg (sub order 1))
418 (take '(%gamma_incomplete) (sub 1 order) arg)))
421 (give-up)))))
423 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
424 ;;; Numerical evaluation of the Exponential Integral En(z)
426 ;;; The following numerical routines are implemented:
428 ;;; expintegral-e - n positive integer, z real or complex
429 ;;; frac-expintegral-e - n,z real or complex; n not a positive integer
430 ;;; bfloat-expintegral-e - n positive integer,
431 ;;; z Bigfloat or Complex Bigfloat
432 ;;; frac-bfloat-expintegral-e - n Bigfloat, z Bigfloat or Complex Bigfloat
434 ;;; The algorithm are implemented for full support of Flonum and Bigfloat real
435 ;;; or Complex parameter and argument of the Exponential Integral.
436 ;;; Because we have no support for Complex Bigfloat arguments of the Gamma
437 ;;; function the evaluation for a Complex Bigfloat parameter don't give
438 ;;; the desiered accuracy.
440 ;;; The flonum versions return a CL complex number. The Bigfloat versions
441 ;;; a Maxima Complex Bigfloat number. It is assumed that the calling routine
442 ;;; check the values. We don't handle any special case. This has to be done by
443 ;;; the calling routine.
445 ;;; The evaluation uses an expansion in continued fractions for arguments with
446 ;;; realpart(z) > 0 and abs(z)> 1.0 (A&S 5.1.22). This expansion works for
447 ;;; every Real or Complex numbers including Bigfloat numbers for the parameter n
448 ;;; and the argument z:
450 ;;; 1 n 1 n+1 2
451 ;;; En(z) = e^(-z) * ( --- --- --- --- --- ... )
452 ;;; z+ 1+ z+ 1+ z+
454 ;;; The continued fraction is evaluated by the modified Lentz's method
455 ;;; for the more rapidly converging even form.
457 ;;; For the parameter n an positive integer we do an expansion in a power series
458 ;;; (A&S 5.1.12):
459 ;;; inf
460 ;;; ===
461 ;;; (-z)^(n-1) \ (-z)^m
462 ;;; En(z) = --------- * (-log(z)+psi(n)) * > ---------- ; n an integer
463 ;;; (n-1)! / (m-n+1)*m!
464 ;;; ===
465 ;;; m=0 (m <> n-1)
467 ;;; For an parameter n not an integer we expand in the following series
468 ;;; (functions.wolfram.com ):
469 ;;; inf
470 ;;; ===
471 ;;; \ (-1)^m * z^m
472 ;;; Ev(z) = gamma(1-v) * z^(v-1) * > ------------- ; n not an integer
473 ;;; / (m-v+1)*m!
474 ;;; ===
475 ;;; m=0
477 ;;; The evaluation stops if an accuracy better than *expint-eps* is achieved.
478 ;;; If the expansion don't converge within *expint-maxit* steps a Maxima
479 ;;; Error is thrown.
481 ;;; The algorithm is based on technics desribed in Numerical Recipes, 2nd Ed.
482 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
484 ;;; Constants to terminate the numerical evaluation
486 ;;; The accuracy *expint-eps* is fixed to 1.0e-15 for double float calculations.
487 ;;; The variable is declared global, so we can later give the Maxima User access
488 ;;; to the variable. The routine for Bigfloat numerical evaluation change this
489 ;;; value to the desired precision of the global $fpprec.
490 ;;; The maximum number of iterations is arbitrary set to 1000. For Bigfloat
491 ;;; evaluation this number is for very Big numbers too small.
493 ;;; The maximum iterations counted for the test file rtest-expintegral.mac are
494 ;;; 101 for Complex Flonum and 1672 for Complex Bigfloat evaluation.
496 (defvar *expint-eps* 1.0e-15)
497 (defvar *expint-maxit* 1000)
499 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
501 (defun expintegral-e (n z)
502 (declare (type integer n))
503 (let ((*expint-eps* *expint-eps*)
504 (*expint-maxit* *expint-maxit*)
505 ;; Add (complex) 0 to get rid of any signed zeroes, and make z
506 ;; be a complex number.
507 (z (+ (coerce 0 '(complex flonum)) z)))
508 (declare (type (complex flonum) z))
510 (when *debug-expintegral*
511 (format t "~&EXPINTEGRAL-E called with:~%")
512 (format t "~& : n = ~A~%" n)
513 (format t "~& : z = ~A~%" z))
515 (cond
516 ((or (and (> (abs z) 2.0) (< (abs (phase z)) (* pi 0.9)))
517 ;; (abs z)>2.0 is necessary since there is a point
518 ;; -1.700598-0.612828*%i which 1<(abs z)<2, phase z < 0.9pi and
519 ;; still c-f expansion does not converge.
520 (and (>= (realpart z) 0) (> (abs z) 1.0)))
521 ;; We expand in continued fractions.
522 (when *debug-expintegral*
523 (format t "~&We expand in continued fractions.~%"))
524 (let* ((b (+ z n))
525 (c (/ 1.0 (* *expint-eps* *expint-eps*)))
526 (d (/ 1.0 b))
527 (n1 (- n 1))
528 (h d)
529 (e 0.0))
530 (do* ((i 1 (+ i 1))
531 (a (* -1 n) (* (- i) (+ n1 i))))
532 ((> i *expint-maxit*)
533 (merror
534 (intl:gettext "expintegral_e: continued fractions failed.")))
536 (setq b (+ b 2.0))
537 (setq d (/ 1.0 (+ (* a d) b)))
538 (setq c (+ b (/ a c)))
539 (setq e (* c d))
540 (setq h (* h e))
542 (when (< (abs (- e 1.0)) *expint-eps*)
543 (when *debug-expintegral*
544 (setq *debug-expint-maxit* (max *debug-expint-maxit* i)))
545 (return (* h (exp (- z))))))))
547 ;; We expand in a power series.
548 (when *debug-expintegral*
549 (format t "~&We expand in a power series.~%"))
550 (let* ((n1 (- n 1))
551 (euler (mget '$%gamma '$numer))
552 (r (if (= n1 0) (- (- euler) (log z)) (/ 1.0 n1)))
553 (f 1.0)
554 (e 0.0))
555 (do ((i 1 (+ i 1)))
556 ((> i *expint-maxit*)
557 (merror (intl:gettext "expintegral_e: series failed.")))
558 (setq f (* -1 f (/ z i)))
559 (cond
560 ((= i n1)
561 (let ((psi (- euler)))
562 (dotimes (ii n1)
563 (setq psi (+ psi (/ 1.0 (+ ii 1)))))
564 (setq e (* f (- psi (log z))))))
566 (setq e (/ (- f) (- i n1)))))
567 (setq r (+ r e))
568 (when (< (abs e) (* (abs r) *expint-eps*))
569 (when *debug-expintegral*
570 (setq *debug-expint-maxit* (max *debug-expint-maxit* i)))
571 (return r))))))))
573 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
574 ;;; Numerical evaluation for a real or complex parameter.
575 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
577 (defun frac-expintegral-e (n z)
578 (declare (type (complex flonum) n)
579 (type (complex flonum) z))
581 (let ((*expint-eps* *expint-eps*)
582 (*expint-maxit* *expint-maxit*))
584 (when *debug-expintegral*
585 (format t "~&FRAC-EXPINTEGRAL-E called with:~%")
586 (format t "~& : n = ~A~%" n)
587 (format t "~& : z = ~A~%" z))
589 (cond
590 ((and (> (realpart z) 0) (> (abs z) 1.0))
591 ;; We expand in continued fractions.
592 (when *debug-expintegral*
593 (format t "~&We expand in continued fractions.~%"))
594 (let* ((b (+ z n))
595 (c (/ 1.0 (* *expint-eps* *expint-eps*)))
596 (d (/ 1.0 b))
597 (n1 (- n 1))
598 (h d)
599 (e 0.0))
600 (do* ((i 1 (+ i 1))
601 (a (* -1 n) (* (- i) (+ n1 i))))
602 ((> i *expint-maxit*)
603 (merror
604 (intl:gettext "expintegral_e: continued fractions failed.")))
606 (setq b (+ b 2.0))
607 (setq d (/ 1.0 (+ (* a d) b)))
608 (setq c (+ b (/ a c)))
609 (setq e (* c d))
610 (setq h (* h e))
612 (when (< (abs (- e 1.0)) *expint-eps*)
613 (when *debug-expintegral*
614 (setq *debug-expint-fracmaxit* (max *debug-expint-fracmaxit* i)))
615 (return (* h (exp (- z))))))))
617 ((and (= (imagpart n) 0)
618 (> (realpart n) 0)
619 (= (nth-value 1 (truncate (realpart n))) 0))
620 ;; We have a positive integer n or an float representation of an
621 ;; integer. We call expintegral-e which does this calculation.
622 (when *debug-expintegral*
623 (format t "~&We call expintegral-e.~%"))
624 (expintegral-e (truncate (realpart n)) z))
627 ;; At this point the parameter n is a real (not an float representation
628 ;; of an integer) or complex. We expand in a power series.
629 (when *debug-expintegral*
630 (format t "~&We expand in a power series.~%"))
631 (let* ((n1 (- n 1))
632 ;; It would be possible to call the numerical implementation
633 ;; gamm-lanczos directly. But then the code would depend on the
634 ;; details of the implementation.
635 (gm (let ((tmp (take '(%gamma) (complexify (- 1 n)))))
636 (complex ($realpart tmp) ($imagpart tmp))))
637 (r (- (* (expt z n1) gm) (/ 1.0 (- 1 n))))
638 (f 1.0)
639 (e 0.0))
640 (do ((i 1 (+ i 1)))
641 ((> i *expint-maxit*)
642 (merror (intl:gettext "expintegral_e: series failed.")))
643 (setq f (* -1 f (/ z (float i))))
644 (setq e (/ (- f) (- (float i) n1)))
645 (setq r (+ r e))
646 (when (< (abs e) (* (abs r) *expint-eps*))
647 (when *debug-expintegral*
648 (setq *debug-expint-fracmaxit* (max *debug-expint-fracmaxit* i)))
649 (return r))))))))
651 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
652 ;;; Helper functions for Bigfloat numerical evaluation.
653 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
655 (defun cmul (x y) ($rectform (mul x y)))
657 (defun cdiv (x y) ($rectform (div x y)))
659 (defun cpower (x y) ($rectform (power x y)))
661 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
662 ;;; We have not changed the above algorithm, but generalized it to handle
663 ;;; complex and real Bigfloat numbers. By carefully examination of the
664 ;;; algorithm some of the additional calls to $rectform can be eliminated.
665 ;;; But the algorithm works and so we leave the extra calls for later work
666 ;;; in the code.
667 ;;; The accuracy of the result is determined by *expint-eps*. The value is
668 ;;; chosen to correspond to the value of $fpprec. We don't give any extra
669 ;;; digits to fpprec, so we loose 1 to 2 digits of precision.
670 ;;; One problem is to chose a sufficient big *expint-maxit*.
671 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
673 (defun bfloat-expintegral-e (n z)
674 (let ((*expint-eps* (power ($bfloat 10.0) (- $fpprec)))
675 (*expint-maxit* 5000) ; arbitrarily chosen, we need a better choice
676 (bigfloattwo (add bigfloatone bigfloatone))
677 (bigfloat%e ($bfloat '$%e))
678 (bigfloat%gamma ($bfloat '$%gamma))
679 (flz (complex ($float ($realpart z)) ($float ($imagpart z)))))
681 (when *debug-expintegral*
682 (format t "~&BFLOAT-EXPINTEGRAL-E called with:~%")
683 (format t "~& : n = ~A~%" n)
684 (format t "~& : z = ~A~%" flz))
686 (cond
687 ((or (and (> (abs flz) 2) (< (abs (phase flz)) (* pi 0.9)))
688 ;; The same condition as you see in expintegral-e()
689 (and (>= (realpart flz) 0) (> (abs flz) 1.0)))
690 ;; We expand in continued fractions.
691 (when *debug-expintegral*
692 (format t "~&We expand in continued fractions.~%"))
693 (let* ((b (add z n))
694 (c (div bigfloatone (mul *expint-eps* *expint-eps*)))
695 (d (cdiv bigfloatone b))
696 (n1 (- n 1))
697 (h d)
698 (e 0.0))
699 (do* ((i 1 (+ i 1))
700 (a (* -1 n) (* (- i) (+ n1 i))))
701 ((> i *expint-maxit*)
702 (merror
703 (intl:gettext "expintegral_e: continued fractions failed.")))
705 (setq b (add b bigfloattwo))
706 (setq d (cdiv bigfloatone (add (mul a d) b)))
707 (setq c (add b (cdiv a c)))
708 (setq e (cmul c d))
709 (setq h (cmul h e))
711 (when (eq ($sign (sub (cabs (sub e bigfloatone)) *expint-eps*))
712 '$neg)
713 (when *debug-expintegral*
714 (setq *debug-expint-bfloatmaxit*
715 (max *debug-expint-bfloatmaxit* i)))
716 (return (cmul h (cpower bigfloat%e (mul -1 z))))))))
718 ;; We expand in a power series.
719 (when *debug-expintegral*
720 (format t "~&We expand in a power series.~%"))
721 (let* ((n1 (- n 1))
722 (meuler (mul -1 bigfloat%gamma))
723 (r (if (= n1 0) (sub meuler ($log z)) (div bigfloatone n1)))
724 (f bigfloatone)
725 (e bigfloatzero))
726 (do* ((i 1 (+ i 1)))
727 ((> i *expint-maxit*)
728 (merror (intl:gettext "expintegral_e: series failed.")))
729 (setq f (mul -1 (cmul f (cdiv z i))))
730 (cond
731 ((= i n1)
732 (let ((psi meuler))
733 (dotimes (ii n1)
734 (setq psi (add psi (cdiv bigfloatone (+ ii 1)))))
735 (setq e (cmul f (sub psi ($log z))))))
737 (setq e (cdiv (mul -1 f) (- i n1)))))
738 (setq r (add r e))
739 (when (eq ($sign (sub (cabs e) (cmul (cabs r) *expint-eps*)))
740 '$neg)
741 (when *debug-expintegral*
742 (setq *debug-expint-bfloatmaxit*
743 (max *debug-expint-bfloatmaxit* i)))
744 (return r))))))))
746 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
747 ;;; Numerical Bigfloat evaluation for a real (Bigfloat) parameter.
748 ;;; The algorithm would work for a Complex Bigfloat parameter too. But we
749 ;;; need the values of Gamma for Complex Bigfloats. This is at this time (2008)
750 ;;; not implemented in Maxima.
751 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
753 (defun frac-bfloat-expintegral-e (n z)
754 (let ((*expint-eps* (power ($bfloat 10.0) (- $fpprec)))
755 (*expint-maxit* 5000) ; arbitrarily chosen, we need a better choice
756 (bigfloattwo (add bigfloatone bigfloatone))
757 (bigfloat%e ($bfloat '$%e))
758 (bigfloat%gamma ($bfloat '$%gamma)))
760 (when *debug-expintegral*
761 (format t "~&FRAC-BFLOAT-EXPINTEGRAL-E called with:~%")
762 (format t "~& : n = ~A~%" n)
763 (format t "~& : z = ~A~%" z))
765 (cond
766 ((and (or (eq ($sign ($realpart z)) '$pos)
767 (eq ($sign ($realpart z)) '$zero))
768 (eq ($sign (sub (cabs z) bigfloatone)) '$pos))
769 ;; We expand in continued fractions.
770 (when *debug-expintegral*
771 (format t "We expand in continued fractions.~%"))
772 (let* ((b (add z n))
773 (c (div bigfloatone (mul *expint-eps* *expint-eps*)))
774 (d (cdiv bigfloatone b))
775 (n1 (sub n 1))
776 (h d)
777 (e 0.0))
778 (do* ((i 1 (+ i 1))
779 (a (mul -1 n) (cmul (- i) (add n1 i))))
780 ((> i *expint-maxit*)
781 (merror
782 (intl:gettext "expintegral_e: continued fractions failed.")))
784 (setq b (add b bigfloattwo))
785 (setq d (cdiv bigfloatone (add (mul a d) b)))
786 (setq c (add b (cdiv a c)))
787 (setq e (cmul c d))
788 (setq h (cmul h e))
790 (when (eq ($sign (sub (cabs (sub e bigfloatone)) *expint-eps*))
791 '$neg)
792 (when *debug-expintegral*
793 (setq *debug-expint-fracbfloatmaxit*
794 (max *debug-expint-fracbfloatmaxit* i)))
795 (return (cmul h (cpower bigfloat%e (mul -1 z))))))))
797 ((or (and (numberp n)
798 (= ($imagpart n) 0)
799 (> ($realpart n) 0)
800 (= (nth-value 1 (truncate ($realpart n))) 0))
801 (and ($bfloatp n)
802 (eq ($sign n) '$pos)
803 (equal (sub (mul 2 ($fix n)) (mul 2 n))
804 bigfloatzero)))
805 ;; We have a Float or Bigfloat representation of positive integer.
806 ;; We call bfloat-expintegral-e.
807 (when *debug-expintegral*
808 (format t "frac-Bigfloat with integer ~A~%" n))
809 (bfloat-expintegral-e ($fix ($realpart n)) z))
812 ;; At this point the parameter n is a real (not a float representation
813 ;; of an integer) or complex. We expand in a power series.
814 (when *debug-expintegral*
815 (format t "We expand in a power series.~%"))
816 (let* ((n1 (sub n bigfloatone))
817 (n2 (sub bigfloatone n))
818 (gm (take '(%gamma) n2))
819 (r (sub (cmul (cpower z n1) gm) (cdiv bigfloatone n2)))
820 (f bigfloatone)
821 (e bigfloatzero))
822 (do ((i 1 (+ i 1)))
823 ((> i *expint-maxit*)
824 (merror (intl:gettext "expintegral_e: series failed.")))
825 (setq f (cmul (mul -1 bigfloatone) (cmul f (cdiv z i))))
826 (setq e (cdiv (mul -1 f) (sub i n1)))
827 (setq r (add r e))
828 (when (eq ($sign (sub (cabs e) (cmul (cabs r) *expint-eps*)))
829 '$neg)
830 (when *debug-expintegral*
831 (setq *debug-expint-fracbfloatmaxit*
832 (max *debug-expint-fracbfloatmaxit* i)))
833 (return r))))))))
835 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
837 ;;; Part 2: The implementation of the Exponential Integral E1
839 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
841 ;;; Exponential Integral E1 distributes over bags
843 (defprop %expintegral_e1 (mlist $matrix mequal) distribute_over)
845 ;;; Exponential Integral E1 has mirror symmetry,
846 ;;; but not on the real negative axis.
848 (defprop %expintegral_e1 conjugate-expintegral-e1 conjugate-function)
850 (defun conjugate-expintegral-e1 (args)
851 (let ((z (first args)))
852 (cond ((off-negative-real-axisp z)
853 ;; Definitely not on the negative real axis for z. Mirror symmetry.
854 (take '(%expintegral_e1) (take '($conjugate) z)))
856 ;; On the negative real axis or no information. Unsimplified.
857 (list '($conjugate simp) (take '(%expintegral_e1) z))))))
859 ;;; Differentiation of Exponential Integral E1
861 (defprop %expintegral_e1
862 ((x)
863 ((mtimes) -1
864 ((mexpt) x -1)
865 ((mexpt) $%e ((mtimes) -1 x))))
866 grad)
868 ;;; Integral of Exponential Integral E1
870 (defprop %expintegral_e1
871 ((z)
872 ((mtimes) -1 ((%expintegral_e) 2 z)))
873 integral)
875 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
877 ;;; We support a simplim%function. The function is looked up in simplimit and
878 ;;; handles specific values of the function.
880 (defprop %expintegral_e1 simplim%expintegral_e1 simplim%function)
882 (defun simplim%expintegral_e1 (expr var val)
883 ;; Look for the limit of the argument.
884 (let ((z (limit (cadr expr) var val 'think)))
885 (cond
886 ;; Handle an argument 0 at this place
887 ((or (zerop1 z)
888 (eq z '$zeroa)
889 (eq z '$zerob))
890 ;; limit is inf from both sides
891 '$inf)
893 ;; All other cases are handled by the simplifier of the function.
894 (take '(%expintegral_e1) z)))))
896 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
898 ;;; Exponential Integral E1 is a simplifying function
899 (def-simplifier expintegral_e1 (arg)
900 (cond
901 ;; Check for special values
902 ((or (eq arg '$inf)
903 (alike1 arg '((mtimes) -1 $minf)))
905 ((zerop1 arg)
906 (simp-domain-error
907 (intl:gettext "expintegral_e1: expintegral_e1(~:M) is undefined.") arg))
909 ;; Check for numerical evaluation
910 ((complex-float-numerical-eval-p arg)
911 ;; For E1 we call En(z) with n=1 directly.
912 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
913 (complexify (expintegral-e 1 carg))))
915 ((complex-bigfloat-numerical-eval-p arg)
916 ;; For E1 we call En(z) with n=1 directly.
917 (let* (($ratprint nil)
918 (carg (add ($bfloat ($realpart arg))
919 (mul '$%i ($bfloat ($imagpart arg)))))
920 (result (bfloat-expintegral-e 1 carg)))
921 (add ($realpart result)
922 (mul '$%i ($imagpart result)))))
924 ;; Check argument simplifications and transformations
925 ((taylorize (mop form) (second form)))
927 ((and $expintrep
928 (member $expintrep *expintflag* :test #'eq)
929 (not (eq $expintrep '%expintegral_e1)))
930 (case $expintrep
931 (%gamma_incomplete
932 (take '(%gamma_incomplete) 0 arg))
933 (%expintegral_ei
934 (add (mul -1 (take '(%expintegral_ei) (mul -1 arg)))
935 (mul (inv 2)
936 (sub (take '(%log) (mul -1 arg))
937 (take '(%log) (mul -1 (inv arg)))))
938 (mul -1 (take '(%log) arg))))
939 (%expintegral_li
940 (add (mul -1 (take '(%expintegral_li) (power '$%e (mul -1 arg))))
941 (mul -1 (take '(%log) arg))
942 (mul (inv 2)
943 (sub (take '(%log) (mul -1 arg))
944 (take '(%log) (mul -1 (inv arg)))))))
945 ($expintegral_trig
946 (add (mul -1 '$%i (take '(%expintegral_si) (mul '$%i arg)))
947 (mul -1 (take '(%expintegral_ci) (mul '$%i arg)))
948 (take '(%log) (mul '$%i arg))
949 (mul -1 (take '(%log) arg))))
950 ($expintegral_hyp
951 (sub (take '(%expintegral_shi) arg)
952 (take '(%expintegral_chi) arg)))
954 (give-up))))
957 (give-up))))
959 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
961 ;;; Part 3: The implementation of the Exponential Integral Ei
963 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
965 ;;; Exponential Integral Ei distributes over bags
967 (defprop %expintegral_ei (mlist $matrix mequal) distribute_over)
969 ;;; Exponential Integral Ei has mirror symmetry
971 (defprop %expintegral_ei t commutes-with-conjugate)
973 ;;; Differentiation of Exponential Integral Ei
975 (defprop %expintegral_ei
976 ((x)
977 ((mtimes) ((mexpt) x -1) ((mexpt) $%e x)))
978 grad)
980 ;;; Integral of Exponential Ei
982 (defprop %expintegral_ei
983 ((x)
984 ((mplus)
985 ((mtimes) -1 ((mexpt) $%e x))
986 ((mtimes) x ((%expintegral_ei) x))))
987 integral)
989 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
991 ;;; We support a simplim%function. The function is looked up in simplimit and
992 ;;; handles specific values of the function.
994 (defprop %expintegral_ei simplim%expintegral_ei simplim%function)
996 (defun simplim%expintegral_ei (expr var val)
997 ;; Look for the limit of the arguments.
998 (let ((z (limit (cadr expr) var val 'think)))
999 (cond
1000 ;; Handle an argument 0 at this place
1001 ((or (zerop1 z)
1002 (eq z '$zeroa)
1003 (eq z '$zerob))
1004 '$minf)
1006 ;; All other cases are handled by the simplifier of the function.
1007 (take '(%expintegral_ei) z)))))
1009 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1011 ;;; Exponential Integral Ei is a simplifying function
1012 (def-simplifier expintegral_ei (arg)
1013 (cond
1014 ;; Check special values
1015 ((zerop1 arg)
1016 (simp-domain-error
1017 (intl:gettext "expintegral_ei: expintegral_ei(~:M) is undefined.")
1018 arg))
1019 ((or (eq arg '$inf)
1020 (alike1 arg '((mtimes) -1 $minf)))
1021 '$inf)
1022 ((or (eq arg '$minf)
1023 (alike1 arg '((mtimes) -1 $inf)))
1025 ((or (alike1 arg '((mtimes) $%i $inf))
1026 (alike1 arg '((mtimes) -1 $%i $minf)))
1027 (mul '$%i '$%pi))
1028 ((or (alike1 arg '((mtimes) $%i $minf))
1029 (alike1 arg '((mtimes) -1 $%i $inf)))
1030 (mul -1 '$%i '$%pi))
1032 ;; Check numerical evaluation
1033 ((complex-float-numerical-eval-p arg)
1034 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1035 (complexify (expintegral-ei carg))))
1037 ((complex-bigfloat-numerical-eval-p arg)
1038 (let* (($ratprint nil)
1039 (carg (add ($bfloat ($realpart arg))
1040 (mul '$%i ($bfloat ($imagpart arg)))))
1041 (result (bfloat-expintegral-ei carg)))
1042 (add ($realpart result)
1043 (mul '$%i ($imagpart result)))))
1045 ;; Check argument simplifications and transformations
1046 ((taylorize (mop form) (second form)))
1048 ((and $expintrep
1049 (member $expintrep *expintflag*)
1050 (not (eq $expintrep '%expintegral_ei)))
1051 (case $expintrep
1052 (%gamma_incomplete
1053 (add (mul -1 (take '(%gamma_incomplete) 0 (mul -1 arg)))
1054 (mul (inv 2)
1055 (sub (take '(%log) arg)
1056 (take '(%log) (inv arg))))
1057 (mul -1 (take '(%log) (mul -1 arg)))))
1058 (%expintegral_e1
1059 (add (mul -1 (take '(%expintegral_e1) (mul -1 arg)))
1060 (mul (inv 2)
1061 (sub (take '(%log) arg)
1062 (take '(%log) (inv arg))))
1063 (mul -1 (take '(%log) (mul -1 arg)))))
1064 (%expintegral_li
1065 (take '(%expintegral_li) (power '$%e arg)))
1066 ($expintegral_trig
1067 (add (take '(%expintegral_ci) (mul '$%i arg))
1068 (mul -1 '$%i (take '(%expintegral_si) (mul '$%i arg)))
1069 (mul (inv -2)
1070 (sub (take '(%log) (inv arg))
1071 (take '(%log) arg)))
1072 (mul -1 (take '(%log) (mul '$%i arg)))))
1073 ($expintegral_hyp
1074 (add (take '(%expintegral_chi) arg)
1075 (take '(%expintegral_shi) arg)
1076 (mul (inv -2)
1077 (add (take '(%log) (inv arg))
1078 (take '(%log) arg)))))))
1081 (give-up))))
1083 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1084 ;;; Numerical evaluation of the Exponential Integral Ei(z):
1086 ;;; We use the following representation (see functions.wolfram.com):
1088 ;;; Ei(z) = -E1(-z) + 0.5*(log(z)-log(1/z))-log(-z)
1090 ;;; z is a CL Complex number. Because we evaluate for Complex values we have to
1091 ;;; take into account the complete Complex phase factors.
1092 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1094 (defun expintegral-ei (z)
1095 (+ (- (expintegral-e 1 (- z)))
1096 ;; Carefully compute 1/2*(log(z)-log(1/z))-log(-z), using the
1097 ;; branch cuts that we want, not the one that Lisp wants.
1098 ;; (Mostly an issue with Lisps that support signed zeroes.)
1099 (cond
1100 ((> (imagpart z) 0)
1101 ;; Positive imaginary part. Add phase %i*%pi.
1102 (complex 0 (float pi)))
1103 ((< (imagpart z) 0)
1104 ;; Negative imaginary part. Add phase -%i*%pi.
1105 (complex 0 (- (float pi))))
1106 ((> (realpart z) 0)
1107 ;; Positive real value. Add phase -%i*pi.
1108 (complex 0 (- (float pi))))
1109 ;; Negative real value. No phase factor.
1110 (t 0))))
1112 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1113 ;;; We have not modified the algorithm for Bigfloat numbers. It is only
1114 ;;; generalized for Bigfloats. The calcualtion of the complex phase factor
1115 ;;; can be simplified to conditions about the sign of the realpart and
1116 ;;; imagpart. We leave this for further work to optimize the speed of the
1117 ;;; calculation.
1118 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1120 (defun bfloat-expintegral-ei (z)
1121 (let ((mz (mul -1 z)))
1122 (add (cmul (mul -1 bigfloatone)
1123 (bfloat-expintegral-e 1 mz))
1124 (sub (cmul (div bigfloatone 2)
1125 (sub (take '(%log) z)
1126 (take '(%log) (cdiv bigfloatone z))))
1127 (take '(%log) mz)))))
1129 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1131 ;;; Part 4: The implementation of the Logarithmic integral li(z)
1133 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1135 ;;; Exponential Integral Li distributes over bags
1137 (defprop %expintegral_li (mlist $matrix mequal) distribute_over)
1139 ;;; Exponential Integral Li has mirror symmetry,
1140 ;;; but not on the real negative axis.
1142 (defprop %expintegral_li conjugate-expintegral-li conjugate-function)
1144 (defun conjugate-expintegral-li (args)
1145 (let ((z (first args)))
1146 (cond ((off-negative-real-axisp z)
1147 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1148 (take '(%expintegral_li) (take '($conjugate) z)))
1150 ;; On the negative real axis or no information. Unsimplified.
1151 (list '($conjugate simp) (take '(%expintegral_li) z))))))
1153 ;;; Differentiation of Exponential Integral Li
1155 (defprop %expintegral_li
1156 ((x)
1157 ((mtimes) ((mexpt) ((%log) x) -1)))
1158 grad)
1160 ;;; Integral of Exponential Li
1162 (defprop %expintegral_li
1163 ((x)
1164 ((mplus)
1165 ((mtimes) x ((%expintegral_li) x))
1166 ((mtimes) -1 ((%expintegral_ei) ((mtimes) 2 ((%log) x))))))
1167 integral)
1169 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1171 ;;; We support a simplim%function. The function is looked up in simplimit and
1172 ;;; handles specific values of the function.
1174 (defprop %expintegral_li simplim%expintegral_li simplim%function)
1176 (defun simplim%expintegral_li (expr var val)
1177 ;; Look for the limit of the argument.
1178 (let ((z (limit (cadr expr) var val 'think)))
1179 (cond
1180 ;; Handle an argument 1 at this place
1181 ((onep1 z) '$minf)
1183 ;; All other cases are handled by the simplifier of the function.
1184 (take '(%expintegral_li) z)))))
1186 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1188 ;;; Exponential Integral Li is a simplifying function
1189 (def-simplifier expintegral_li (arg)
1190 (cond
1191 ((zerop1 arg) arg)
1192 ((onep1 arg)
1193 (simp-domain-error
1194 (intl:gettext "expintegral_li: expintegral_li(~:M) is undefined.") arg))
1195 ((or (eq arg '$inf)
1196 (alike1 arg '((mtimes) -1 $minf)))
1197 '$inf)
1198 ((eq arg '$infinity) '$infinity)
1200 ((complex-float-numerical-eval-p arg)
1201 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1202 (complexify (expintegral-li carg))))
1204 ((complex-bigfloat-numerical-eval-p arg)
1205 (let* (($ratprint nil)
1206 (carg (add ($bfloat ($realpart arg))
1207 (mul '$%i ($bfloat ($imagpart arg)))))
1208 (result (bfloat-expintegral-li carg)))
1209 (add (mul '$%i ($imagpart result))
1210 ($realpart result))))
1212 ;; Check for argument simplifications and transformations
1213 ((taylorize (mop form) (second form)))
1215 ((and $expintrep
1216 (member $expintrep *expintflag*)
1217 (not (eq $expintrep '%expintegral_li)))
1218 (let ((logarg (take '(%log) arg)))
1219 (case $expintrep
1220 (%gamma_incomplete
1221 (add (mul -1 (take '(%gamma_incomplete) 0 (mul -1 logarg)))
1222 (mul (inv 2)
1223 (sub (take '(%log) logarg)
1224 (take '(%log) (inv logarg))))
1225 (mul -1 (take '(%log) (mul -1 logarg)))))
1226 (%expintegral_e1
1227 (add (mul -1 (take '(%expintegral_e1) (mul -1 logarg)))
1228 (mul (inv 2)
1229 (sub (take '(%log) logarg)
1230 (take '(%log) (inv logarg))))
1231 (mul -1 (take '(%log) (mul -1 logarg)))))
1232 (%expintegral_ei
1233 ($expintegral_ei logarg))
1234 ($expintegral_trig
1235 (add (take '(%expintegral_ci) (mul '$%i logarg))
1236 (mul -1 '$%i (take '(%expintegral_si) (mul '$%i logarg)))
1237 (mul (inv -2)
1238 (sub (take '(%log) (inv logarg))
1239 (take '(%log) logarg)))
1240 (mul -1 (take '(%log) (mul '$%i logarg)))))
1241 ($expintegral_hyp
1242 (add (take '(%expintegral_chi) logarg)
1243 (take '(%expintegral_shi) logarg)
1244 (mul (inv -2)
1245 (add (take '(%log) (inv logarg))
1246 (take '(%log) logarg))))))))
1249 (give-up))))
1251 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1252 ;;; Numerical evaluation of the Expintegral Li
1254 ;;; We use the representation:
1256 ;;; Li(z) = Ei(log(z))
1257 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1259 (defun expintegral-li (z)
1260 (expintegral-ei (log z)))
1262 (defun bfloat-expintegral-li (z)
1263 (bfloat-expintegral-ei ($log z)))
1265 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1267 ;;; Part 5: The implementation of the Exponential Integral Si
1269 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1271 ;;; Exponential Integral Si distributes over bags
1273 (defprop %expintegral_si (mlist $matrix mequal) distribute_over)
1275 ;;; Exponential Integral Si has mirror symmetry
1277 (defprop %expintegral_si t commutes-with-conjugate)
1279 ;;; Exponential Integral Si is a odd function
1281 (defprop %expintegral_si odd-function-reflect reflection-rule)
1283 ;;; Differentiation of Exponential Integral Si
1285 (defprop %expintegral_si
1286 ((x)
1287 ((mtimes) ((%sin) x) ((mexpt) x -1)))
1288 grad)
1290 ;;; Integral of Exponential Si
1292 (defprop %expintegral_si
1293 ((x)
1294 ((mplus)
1295 ((%cos) x)
1296 ((mtimes) x ((%expintegral_si) x))))
1297 integral)
1299 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1301 ;;; We support a simplim%function.
1303 (defprop %expintegral_si simplim%expintegral_si simplim%function)
1305 (defun simplim%expintegral_si (expr var val)
1306 ;; Look for the limit of the argument.
1307 (let ((z (limit (cadr expr) var val 'think)))
1308 ;; All cases are handled by the simplifier of the function.
1309 (take '(%expintegral_si) z)))
1311 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1313 ;;; Exponential Integral Si is a simplifying function
1314 (def-simplifier expintegral_si (arg)
1315 (cond
1316 ;; Check for special values
1317 ((zerop1 arg) arg)
1318 ((or (eq arg '$inf)
1319 (alike1 arg '((mtimes) -1 $minf)))
1320 (div '$%pi 2))
1321 ((or (eq arg '$minf)
1322 (alike1 arg '((mtimes) -1 $inf)))
1323 (mul -1 (div '$%pi 2)))
1325 ;; Check for numerical evaluation
1326 ((complex-float-numerical-eval-p arg)
1327 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1328 (complexify (expintegral-si carg))))
1330 ((complex-bigfloat-numerical-eval-p arg)
1331 (let* (($ratprint nil)
1332 (carg (add ($bfloat ($realpart arg))
1333 (mul '$%i ($bfloat ($imagpart arg)))))
1334 (result (bfloat-expintegral-si carg)))
1335 (add (mul '$%i ($imagpart result))
1336 ($realpart result))))
1338 ;; Check for argument simplifications and transformations
1339 ((taylorize (mop form) (second form)))
1340 ((apply-reflection-simp (mop form) arg $trigsign))
1342 ((and $expintrep
1343 (member $expintrep *expintflag*)
1344 (not (eq $expintrep '$expintegral_trig)))
1345 (case $expintrep
1346 (%gamma_incomplete
1347 (mul (div '$%i 2)
1348 (add (take '(%gamma_incomplete) 0 (mul -1 '$%i arg))
1349 (mul -1 (take '(%gamma_incomplete) 0 (mul '$%i arg)))
1350 (take '(%log) (mul -1 '$%i arg))
1351 (mul -1 (take '(%log) (mul '$%i arg))))))
1352 (%expintegral_e1
1353 (mul (div '$%i 2)
1354 (add (take '(%expintegral_e1) (mul -1 '$%i arg))
1355 (mul -1 (take '(%expintegral_e1) (mul '$%i arg)))
1356 (take '(%log) (mul -1 '$%i arg))
1357 (mul -1 (take '(%log) (mul '$%i arg))))))
1358 (%expintegral_ei
1359 (mul (div '$%i 4)
1360 (add (mul 2
1361 (sub (take '(%expintegral_ei) (mul -1 '$%i arg))
1362 (take '(%expintegral_ei) (mul '$%i arg))))
1363 (take '(%log) (div '$%i arg))
1364 (mul -1 (take '(%log) (mul -1 (div '$%i arg))))
1365 (mul -1 (take '(%log) (mul -1 '$%i arg)))
1366 (take '(%log) (mul '$%i arg)))))
1367 (%expintegral_li
1368 (mul (inv (mul 2 '$%i))
1369 (add (take '(%expintegral_li) (power '$%e (mul '$%i arg)))
1370 (mul -1
1371 (take '(%expintegral_li)
1372 (power '$%e (mul -1 '$%e arg))))
1373 (mul (div '$%pi -2)
1374 (take '(%signum) ($realpart arg))))))
1375 ($expintegral_hyp
1376 (mul -1 '$%i (take '(%expintegral_shi) (mul '$%i arg))))))
1379 (give-up))))
1381 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1382 ;;; Numerical evaluation of the Exponential Integral Si
1384 ;;; We use the representation:
1386 ;;; Si(z) = %i/2 * (E1(-%i*z) - E1(*%i*z) + log(%i*z) - log(-%i*z))
1388 ;;; For the Sin, Cos, Sinh and Cosh Exponential Integrals we have to call the
1389 ;;; numerical evaluation twice. In principle we could use a direct expansion
1390 ;;; in a power series or continued fractions to optimize the speed of the code.
1391 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1393 (defun expintegral-si (z)
1394 (let ((z (coerce z '(complex flonum))))
1395 (* (complex 0 0.5)
1396 (+ (expintegral-e 1 (* (complex 0 -1) z))
1397 (- (expintegral-e 1 (* (complex 0 1) z)))
1398 (log (* (complex 0 -1) z))
1399 (- (log (* (complex 0 1) z)))))))
1401 (defun bfloat-expintegral-si (z)
1402 (let ((z*%i (cmul '$%i z))
1403 (mz*%i (cmul (mul -1 '$%i) z)))
1404 (cmul
1405 (mul 0.5 '$%i)
1406 (add
1407 (bfloat-expintegral-e 1 mz*%i)
1408 (mul -1 (bfloat-expintegral-e 1 z*%i))
1409 ($log mz*%i)
1410 (mul -1 ($log z*%i))))))
1412 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1414 ;;; Part 6: The implementation of the Exponential Integral Shi
1416 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1418 ;;; Exponential Integral Shi distributes over bags
1420 (defprop %expintegral_shi (mlist $matrix mequal) distribute_over)
1422 ;;; Exponential Integral Shi has mirror symmetry
1424 (defprop %expintegral_si t commutes-with-conjugate)
1426 ;;; Exponential Integral Shi is a odd function
1428 (defprop %expintegral_si odd-function-reflect reflection-rule)
1430 ;;; Differentiation of Exponential Integral Shi
1432 (defprop %expintegral_shi
1433 ((x)
1434 ((mtimes) ((%sinh) x) ((mexpt) x -1)))
1435 grad)
1437 ;;; Integral of Exponential Shi
1439 (defprop %expintegral_shi
1440 ((x)
1441 ((mplus)
1442 ((mtimes) -1 ((%cosh) x))
1443 ((mtimes) x ((%expintegral_shi) x))))
1444 integral)
1446 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1448 ;;; We support a simplim%function. The function is looked up in simplimit and
1449 ;;; handles specific values of the function.
1451 (defprop %expintegral_shi simplim%expintegral_shi simplim%function)
1453 (defun simplim%expintegral_shi (expr var val)
1454 ;; Look for the limit of the argument.
1455 (let ((z (limit (cadr expr) var val 'think)))
1456 (cond
1457 ;; Handle infinities at this place
1458 ((eq z '$inf)
1459 '$inf)
1460 ((eq z '$minf)
1461 '$minf)
1463 ;; All other cases are handled by the simplifier of the function.
1464 (take '(%expintegral_shi) z)))))
1466 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1468 ;;; Exponential Integral Shi is a simplifying function
1469 (def-simplifier expintegral_shi (arg)
1470 (cond
1471 ;; Check for special values
1472 ((zerop1 arg) arg)
1473 ((or (alike1 arg '((mtimes) $%i $inf))
1474 (alike1 arg '((mtimes) -1 $%i $minf)))
1475 (div (mul '$%i '$%pi) 2))
1476 ((or (alike1 arg '((mtimes) $%i $minf))
1477 (alike1 arg '((mtimes) -1 $%i $inf)))
1478 (div (mul -1 '$%i '$%pi) 2))
1480 ;; Check for numrical evaluation
1481 ((float-numerical-eval-p arg)
1482 (realpart (expintegral-shi arg)))
1484 ((complex-float-numerical-eval-p arg)
1485 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1486 (complexify (expintegral-shi carg))))
1488 ((complex-bigfloat-numerical-eval-p arg)
1489 (let* (($ratprint nil)
1490 (carg (add ($bfloat ($realpart arg))
1491 (mul '$%i ($bfloat ($imagpart arg)))))
1492 (result (bfloat-expintegral-shi carg)))
1493 (add (mul '$%i ($imagpart result))
1494 ($realpart result))))
1496 ;; Check for argument simplifications and transformations
1497 ((taylorize (mop form) (second form)))
1498 ((apply-reflection-simp (mop form) arg $trigsign))
1500 ((and $expintrep
1501 (member $expintrep *expintflag*)
1502 (not (eq $expintrep '$expintegral_hyp)))
1503 (case $expintrep
1504 (%gamma_incomplete
1505 (mul (inv 2)
1506 (add (take '(%gamma_incomplete) 0 arg)
1507 (mul -1 (take '(%gamma_incomplete) 0 (mul -1 arg)))
1508 (mul -1 (take '(%log) (mul -1 arg)))
1509 (take '(%log) arg))))
1510 (%expintegral_e1
1511 (mul (inv 2)
1512 (add (take '(%expintegral_e1) arg)
1513 (mul -1 (take '(%expintegral_e1) (mul -1 arg)))
1514 (mul -1 (take '(%log) (mul -1 arg)))
1515 (take '(%log) arg))))
1516 (%expintegral_ei
1517 (mul (inv 4)
1518 (add (mul 2
1519 (sub (take '(%expintegral_ei) arg)
1520 (take '(%expintegral_ei) (mul -1 arg))))
1521 (take '(%log) (inv arg))
1522 (mul -1 (take '(%log) (mul -1 (inv arg))))
1523 (take '(%log) (mul -1 arg))
1524 (mul -1 (take '(%log) arg)))))
1525 (%expintegral_li
1526 (add (mul (inv 2)
1527 (sub (take '(%expintegral_li) (power '$%e arg))
1528 (take '(%expintegral_li) (power '$%e (mul -1 arg)))))
1529 (mul (div (mul '$%i '$%pi) -2)
1530 (take '(%signum) ($imagpart arg)))))
1531 ($expintegral_trig
1532 (mul -1 '$%i (take '(%expintegral_si) (mul '$%i arg))))))
1535 (give-up))))
1537 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1538 ;;; Numerical evaluation of the Exponential Integral Shi
1540 ;;; We use the representation:
1542 ;;; Shi(z) = 1/2 * (E1(z) - E1(-z) - log(-z) + log(z))
1544 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1546 (defun expintegral-shi (z)
1550 (expintegral-e 1 z)
1551 (- (expintegral-e 1 (- z)))
1552 (- (log (- z)))
1553 (log z))))
1555 (defun bfloat-expintegral-shi (z)
1556 (let ((mz (mul -1 z)))
1557 (mul
1559 (add
1560 (bfloat-expintegral-e 1 z)
1561 (mul -1 (bfloat-expintegral-e 1 mz))
1562 (mul -1 ($log mz))
1563 ($log z)))))
1565 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1567 ;;; Part 7: The implementation of the Exponential Integral Ci
1569 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1571 ;;; Exponential Integral Ci distributes over bags
1573 (defprop %expintegral_ci (mlist $matrix mequal) distribute_over)
1575 ;;; Exponential Integral Ci has mirror symmetry,
1576 ;;; but not on the real negative axis.
1578 (defprop %expintegral_ci conjugate-expintegral-ci conjugate-function)
1580 (defun conjugate-expintegral-ci (args)
1581 (let ((z (first args)))
1582 (cond ((off-negative-real-axisp z)
1583 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1584 (take '(%expintegral_ci) (take '($conjugate) z)))
1586 ;; On the negative real axis or no information. Unsimplified.
1587 (list '($conjugate simp) (take '(%expintegral_ci) z))))))
1589 ;;; Differentiation of Exponential Integral Ci
1591 (defprop %expintegral_ci
1592 ((x)
1593 ((mtimes) ((%cos) x) ((mexpt) x -1)))
1594 grad)
1596 ;;; Integral of Exponential Ci
1598 (defprop %expintegral_ci
1599 ((x)
1600 ((mplus)
1601 ((mtimes) x ((%expintegral_ci) x))
1602 ((mtimes) -1 ((%sin) x))))
1603 integral)
1605 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1607 ;;; We support a simplim%function. The function is looked up in simplimit and
1608 ;;; handles specific values of the function.
1610 (defprop %expintegral_ci simplim%expintegral_ci simplim%function)
1612 (defun simplim%expintegral_ci (expr var val)
1613 ;; Look for the limit of the argument.
1614 (let ((z (limit (cadr expr) var val 'think)))
1615 (cond
1616 ;; Handle an argument 0 at this place
1617 ((or (zerop1 z)
1618 (eq z '$zeroa)
1619 (eq z '$zerob))
1620 '$minf)
1622 ;; All other cases are handled by the simplifier of the function.
1623 (take '(%expintegral_ci) z)))))
1625 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1627 ;;; Exponential Integral Ci is a simplifying function
1628 (def-simplifier expintegral_ci (arg)
1629 (cond
1630 ;; Check for special values
1631 ((zerop1 arg)
1632 (simp-domain-error
1633 (intl:gettext "expintegral_ci: expintegral_ci(~:M) is undefined.") arg))
1634 ((or (eq arg '$inf)
1635 (alike1 arg '((mtimes) -1 $minf)))
1637 ((or (eq arg '$minf)
1638 (alike1 arg '((mtimes) -1 $inf)))
1639 (mul '$%i '$%pi))
1641 ;; Check for numerical evaluation
1642 ((complex-float-numerical-eval-p arg)
1643 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1644 (complexify (expintegral-ci carg))))
1646 ((complex-bigfloat-numerical-eval-p arg)
1647 (let* (($ratprint nil)
1648 (carg (add ($bfloat ($realpart arg))
1649 (mul '$%i ($bfloat ($imagpart arg)))))
1650 (result (bfloat-expintegral-ci carg)))
1651 (add (mul '$%i ($imagpart result))
1652 ($realpart result))))
1654 ;; Check for argument simplifications and transformations
1655 ((taylorize (mop form) (second form)))
1657 ((and $expintrep
1658 (member $expintrep *expintflag*)
1659 (not (eq $expintrep '$expintegral_trig)))
1660 (case $expintrep
1661 (%gamma_incomplete
1662 (sub (take '(%log) arg)
1663 (mul (inv 2)
1664 (add (take '(%gamma_incomplete) 0 (mul -1 '$%i arg))
1665 (take '(%gamma_incomplete) 0 (mul '$%i arg))
1666 (take '(%log) (mul -1 '$%i arg))
1667 (take '(%log) (mul '$%i arg))))))
1668 (%expintegral_e1
1669 (add (mul (inv -2)
1670 (add (take '(%expintegral_e1) (mul -1 '$%i arg))
1671 (take '(%expintegral_e1) (mul '$%i arg)))
1672 (take '(%log) (mul -1 '$%i arg))
1673 (take '(%log) (mul '$%i arg)))
1674 (take '(%log) arg)))
1675 (%expintegral_ei
1676 (add (mul (inv 4)
1677 (add (mul 2
1678 (add (take '(%expintegral_ei) (mul -1 '$%i arg))
1679 (take '(%expintegral_ei) (mul '$%i arg))))
1680 (take '(%log) (div '$%i arg))
1681 (take '(%log) (mul -1 '$%i (inv arg)))
1682 (mul -1 (take '(%log) (mul -1 '$%i arg)))
1683 (mul -1 (take '(%log) (mul '$%i arg)))))
1684 (take '(%log) arg)))
1685 (%expintegral_li
1686 (add (mul (inv 2)
1687 (add (take '(%expintegral_li)
1688 (power '$%e (mul -1 '$%i arg)))
1689 (take '(%expintegral_li)
1690 (power '$%e (mul '$%i arg)))))
1691 (mul (div (mul '$%i '$%pi) 2)
1692 (take '(%signum) ($imagpart arg)))
1693 (sub 1 (take '(%signum) ($realpart arg)))))
1694 ($expintegral_hyp
1695 (add (take '(%expintegral_chi) (mul '$%i arg))
1696 (mul -1 (take '(%log) (mul '$%i arg)))
1697 (take '(%log) arg)))))
1700 (give-up))))
1702 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1703 ;;; Numerical evaluation of the Exponential Integral Ci
1705 ;;; We use the representation:
1707 ;;; Ci(z) = -1/2 * (E1(-%i*z) + E1(%i*z) + log(-%i*z) + log(%i*z)) + log(z)
1709 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1711 (defun expintegral-ci (z)
1712 (let ((z (coerce z '(complex flonum))))
1713 (+ (* -0.5
1714 (+ (expintegral-e 1 (* (complex 0 -1) z))
1715 (expintegral-e 1 (* (complex 0 1) z))
1716 (log (* (complex 0 -1) z))
1717 (log (* (complex 0 1) z))))
1718 (log z))))
1720 (defun bfloat-expintegral-ci (z)
1721 (let ((z*%i (cmul '$%i z))
1722 (mz*%i (cmul (mul -1 '$%i) z)))
1723 (add
1724 (cmul
1725 -0.5
1726 (add
1727 (bfloat-expintegral-e 1 mz*%i)
1728 (bfloat-expintegral-e 1 z*%i)
1729 ($log mz*%i)
1730 ($log z*%i)))
1731 ($log z))))
1733 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1735 ;;; Part 8: The implementation of the Exponential Integral Chi
1737 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1739 ;;; Exponential Integral Chi distributes over bags
1741 (defprop %expintegral_chi (mlist $matrix mequal) distribute_over)
1743 ;;; Exponential Integral Chi has mirror symmetry,
1744 ;;; but not on the real negative axis.
1746 (defprop %expintegral_chi conjugate-expintegral-chi conjugate-function)
1748 (defun conjugate-expintegral-chi (args)
1749 (let ((z (first args)))
1750 (cond ((off-negative-real-axisp z)
1751 ;; Definitely not on the negative real axis for z. Mirror symmetry.
1752 (take '(%expintegral_chi) (take '($conjugate) z)))
1754 ;; On the negative real axis or no information. Unsimplified.
1755 (list '($conjugate simp) (take '(%expintegral_chi) z))))))
1757 ;;; Differentiation of Exponential Integral Chi
1759 (defprop %expintegral_chi
1760 ((x)
1761 ((mtimes) ((%cosh) x) ((mexpt) x -1)))
1762 grad)
1764 ;;; Integral of Exponential Chi
1766 (defprop %expintegral_chi
1767 ((x)
1768 ((mplus)
1769 ((mtimes) x ((%expintegral_chi) x))
1770 ((mtimes) -1 ((%sinh) x))))
1771 integral)
1773 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1775 ;;; We support a simplim%function. The function is looked up in simplimit and
1776 ;;; handles specific values of the function.
1778 (defprop %expintegral_chi simplim%expintegral_chi simplim%function)
1780 (defun simplim%expintegral_chi (expr var val)
1781 ;; Look for the limit of the argument.
1782 (let ((z (limit (cadr expr) var val 'think)))
1783 (cond
1784 ;; Handle an argument 0 at this place
1785 ((or (zerop1 z)
1786 (eq z '$zeroa)
1787 (eq z '$zerob))
1788 '$minf)
1789 ((or (eq z '$inf)
1790 (eq z '$minf))
1791 '$inf)
1793 ;; All other cases are handled by the simplifier of the function.
1794 (take '(%expintegral_chi) z)))))
1796 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1798 ;;; Exponential Integral Chi is a simplifying function
1799 (def-simplifier expintegral_chi (arg)
1800 (cond
1801 ;; Check for special values
1802 ((zerop1 arg)
1803 ;; First check for zero argument. Throw Maxima error.
1804 (simp-domain-error
1805 (intl:gettext "expintegral_chi: expintegral_chi(~:M) is undefined.")
1806 arg))
1807 ((or (alike1 arg '((mtimes) $%i $inf))
1808 (alike1 arg '((mtimes) -1 $%i $minf)))
1809 (div (mul '$%pi '$%i) 2))
1810 ((or (alike1 arg '((mtimes) $%i $minf))
1811 (alike1 arg '((mtimes) -1 $%i $inf)))
1812 (div (mul -1 '$%pi '$%i) 2))
1814 ;; Check for numerical evaluation
1815 ((complex-float-numerical-eval-p arg)
1816 (let ((carg (complex ($float ($realpart arg)) ($float ($imagpart arg)))))
1817 (complexify (expintegral-chi carg))))
1819 ((complex-bigfloat-numerical-eval-p arg)
1820 (let* (($ratprint nil)
1821 (carg (add ($bfloat ($realpart arg))
1822 (mul '$%i ($bfloat ($imagpart arg)))))
1823 (result (bfloat-expintegral-chi carg)))
1824 (add (mul '$%i ($imagpart result))
1825 ($realpart result))))
1827 ;; Check for argument simplifications and transformations
1828 ((taylorize (mop form) (second form)))
1830 ((and $expintrep
1831 (member $expintrep *expintflag*)
1832 (not (eq $expintrep '$expintegral_hyp)))
1833 (case $expintrep
1834 (%gamma_incomplete
1835 (mul (inv -2)
1836 (add (take '(%gamma_incomplete) 0 (mul -1 arg))
1837 (take '(%gamma_incomplete) 0 arg)
1838 (take '(%log) (mul -1 arg))
1839 (mul -1 (take '(%log) arg)))))
1840 (%expintegral_e1
1841 (mul (inv -2)
1842 (add (take '(%expintegral_e1) (mul -1 arg))
1843 (take '(%expintegral_e1) arg)
1844 (take '(%log) (mul -1 arg))
1845 (mul -1 (take '(%log) arg)))))
1846 (%expintegral_ei
1847 (mul (inv 4)
1848 (add (mul 2
1849 (add (take '(%expintegral_ei) (mul -1 arg))
1850 (take '(%expintegral_ei) arg)))
1851 (take '(%log) (inv arg))
1852 (take '(%log) (mul -1 (inv arg)))
1853 (mul -1 (take '(%log) (mul -1 arg)))
1854 (mul 3 (take '(%log) arg)))))
1855 (%expintegral_li
1856 (add (mul (inv 2)
1857 (add (take '(%expintegral_li) (power '$%e (mul -1 arg)))
1858 (take '(%expintegral_li) (power '$%e arg))))
1859 (mul (div (mul '$%i '$%pi) 2)
1860 (take '(%signum) ($imagpart arg)))
1861 (mul (inv 2)
1862 (add (take '(%log) (inv arg))
1863 (take '(%log) arg)))))
1864 ($expintegral_trig
1865 (add (take '(%expintegral_ci) (mul '$%i arg))
1866 (take '(%log) arg)
1867 (mul -1 (take '(%log) (mul '$%i arg)))))))
1870 (give-up))))
1872 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1873 ;;; Numerical evaluation of the Exponential Integral Ci
1875 ;;; We use the representation:
1877 ;;; Chi(z) = -1/2 * (E1(-z) + E1(z) + log(-z) - log(z))
1879 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1881 (defun expintegral-chi (z)
1883 -0.5
1885 (expintegral-e 1 z)
1886 (expintegral-e 1 (- z))
1887 (log (- z))
1888 (- (log z)))))
1890 (defun bfloat-expintegral-chi (z)
1891 (let ((mz (mul -1 z)))
1892 (mul
1893 -0.5
1894 (add
1895 (bfloat-expintegral-e 1 z)
1896 (bfloat-expintegral-e 1 mz)
1897 ($log mz)
1898 (mul -1 ($log z))))))
1900 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1901 ;; Moved from bessel.lisp 2008-12-11. Consider deleting it.
1903 ;; Exponential integral E1(x). The Cauchy principal value is used for
1904 ;; negative x.
1905 (defmfun $expint (x)
1906 (cond ((numberp x)
1907 (values (slatec:de1 (float x))))
1909 (list '($expint simp) x))))