Extend laplace(t^z,t,s) to complex z
[maxima.git] / src / ellipt.lisp
blob08448f8d5446c0c733abc21939a2568c45f2aef1
1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10-*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancments. ;;;;;
4 ;;; ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;; ;;;;;
8 ;;; Copyright (c) 2001 by Raymond Toy. Replaced everything and added ;;;;;
9 ;;; support for symbolic manipulation of all 12 Jacobian elliptic ;;;;;
10 ;;; functions and the complete and incomplete elliptic integral ;;;;;
11 ;;; of the first, second and third kinds. ;;;;;
12 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14 (in-package :maxima)
15 ;;(macsyma-module ellipt)
17 (defvar 3//2 '((rat simp) 3 2))
18 (defvar 1//2 '((rat simp) 1 2))
19 (defvar -1//2 '((rat simp) -1 2))
21 ;;;
22 ;;; Jacobian elliptic functions and elliptic integrals.
23 ;;;
24 ;;; References:
25 ;;;
26 ;;; [1] Abramowitz and Stegun
27 ;;; [2] Lawden, Elliptic Functions and Applications, Springer-Verlag, 1989
28 ;;; [3] Whittaker & Watson, A Course of Modern Analysis
29 ;;;
30 ;;; We use the definitions from Abramowitz and Stegun where our
31 ;;; sn(u,m) is sn(u|m). That is, the second arg is the parameter,
32 ;;; instead of the modulus k or modular angle alpha.
33 ;;;
34 ;;; Note that m = k^2 and k = sin(alpha).
35 ;;;
37 ;; Setup noun/verb for elliptic functions
39 (macrolet
40 ((frob (root)
41 (let* ((s (string root))
42 (forward (concatenate 'string (string 'jacobi_) s))
43 (f-noun (intern (concatenate 'string "%" forward)))
44 (f-verb (intern (concatenate 'string "$" forward)))
45 (inverse (concatenate 'string (string 'inverse_jacobi_) s))
46 (i-noun (intern (concatenate 'string "%" inverse)))
47 (i-verb (intern (concatenate 'string "$" inverse))))
48 `(progn
49 (defprop ,f-verb ,f-noun verb)
50 (defprop ,f-noun ,f-verb noun)
51 (defprop ,f-verb ,f-noun alias)
52 (defprop ,f-noun ,f-verb reversealias)
53 (defprop ,i-verb ,i-noun verb)
54 (defprop ,i-noun ,i-verb noun)
55 (defprop ,i-verb ,i-noun alias)
56 (defprop ,i-noun ,i-verb reversealias)))))
57 (frob sn)
58 (frob cn)
59 (frob dn)
60 (frob ns)
61 (frob nc)
62 (frob nd)
63 (frob sc)
64 (frob cs)
65 (frob sd)
66 (frob ds)
67 (frob cd)
68 (frob dc))
70 (defprop $elliptic_f $elliptic_f verb)
71 (defprop $elliptic_e $elliptic_e verb)
73 ;; Routines for computing the basic elliptic functions sn, cn, and dn.
76 ;; A&S gives several methods for computing elliptic functions
77 ;; including the AGM method (16.4) and ascending and descending Landen
78 ;; transformations (16.12 and 16.14). The latter are actually quite
79 ;; fast, only requiring simple arithmetic and square roots for the
80 ;; transformation until the last step. The AGM requires evaluation of
81 ;; several trigonometric functions at each stage.
83 ;; However, the Landen transformations appear to have some round-off
84 ;; issues. For example, using the ascending transform to compute cn,
85 ;; cn(100,.7) > 1e10. This is clearly not right since |cn| <= 1.
88 (in-package #-gcl #:bigfloat #+gcl "BIGFLOAT")
90 (declaim (inline descending-transform ascending-transform))
92 (defun ascending-transform (u m)
93 ;; A&S 16.14.1
95 ;; Take care in computing this transform. For the case where
96 ;; m is complex, we should compute sqrt(mu1) first as
97 ;; (1-sqrt(m))/(1+sqrt(m)), and then square this to get mu1.
98 ;; If not, we may choose the wrong branch when computing
99 ;; sqrt(mu1).
100 (let* ((root-m (sqrt m))
101 (mu (/ (* 4 root-m)
102 (expt (1+ root-m) 2)))
103 (root-mu1 (/ (- 1 root-m) (+ 1 root-m)))
104 (v (/ u (1+ root-mu1))))
105 (values v mu root-mu1)))
107 (defun descending-transform (u m)
108 ;; Note: Don't calculate mu first, as given in 16.12.1. We
109 ;; should calculate sqrt(mu) = (1-sqrt(m1)/(1+sqrt(m1)), and
110 ;; then compute mu = sqrt(mu)^2. If we calculate mu first,
111 ;; sqrt(mu) loses information when m or m1 is complex.
112 (let* ((root-m1 (sqrt (- 1 m)))
113 (root-mu (/ (- 1 root-m1) (+ 1 root-m1)))
114 (mu (* root-mu root-mu))
115 (v (/ u (1+ root-mu))))
116 (values v mu root-mu)))
119 ;; This appears to work quite well for both real and complex values
120 ;; of u.
121 (defun elliptic-sn-descending (u m)
122 (cond ((= m 1)
123 ;; A&S 16.6.1
124 (tanh u))
125 ((< (abs m) (epsilon u))
126 ;; A&S 16.6.1
127 (sin u))
129 (multiple-value-bind (v mu root-mu)
130 (descending-transform u m)
131 (let* ((new-sn (elliptic-sn-descending v mu)))
132 (/ (* (1+ root-mu) new-sn)
133 (1+ (* root-mu new-sn new-sn))))))))
135 ;; AGM scale. See A&S 17.6
137 ;; The AGM scale is
139 ;; a[n] = (a[n-1]+b[n-1])/2, b[n] = sqrt(a[n-1]*b[n-1]), c[n] = (a[n-1]-b[n-1])/2.
141 ;; We stop when abs(c[n]) <= 10*eps
143 ;; A list of (n a[n] b[n] c[n]) is returned.
144 (defun agm-scale (a b c)
145 (loop for n from 0
146 while (> (abs c) (* 10 (epsilon c)))
147 collect (list n a b c)
148 do (psetf a (/ (+ a b) 2)
149 b (sqrt (* a b))
150 c (/ (- a b) 2))))
152 ;; WARNING: This seems to have accuracy problems when u is complex. I
153 ;; (rtoy) do not know why. For example (jacobi-agm #c(1e0 1e0) .7e0)
154 ;; returns
156 ;; #C(1.134045970915582 0.3522523454566013)
157 ;; #C(0.57149659007575 -0.6989899153338323)
158 ;; #C(0.6229715431044184 -0.4488635962149656)
160 ;; But the actual value of sn(1+%i, .7) is .3522523469224946 %i +
161 ;; 1.134045971912365. We've lost about 7 digits of accuracy!
162 (defun jacobi-agm (u m)
163 ;; A&S 16.4.
165 ;; Compute the AGM scale with a = 1, b = sqrt(1-m), c = sqrt(m).
167 ;; Then phi[N] = 2^N*a[N]*u and compute phi[n] from
169 ;; sin(2*phi[n-1] - phi[n]) = c[n]/a[n]*sin(phi[n])
171 ;; Finally,
173 ;; sn(u|m) = sin(phi[0]), cn(u|m) = cos(phi[0])
174 ;; dn(u|m) = cos(phi[0])/cos(phi[1]-phi[0])
176 ;; Returns the three values sn, cn, dn.
177 (let* ((agm-data (nreverse (rest (agm-scale 1 (sqrt (- 1 m)) (sqrt m)))))
178 (phi (destructuring-bind (n a b c)
179 (first agm-data)
180 (declare (ignore b c))
181 (* a u (ash 1 n))))
182 (phi1 0e0))
183 (dolist (agm agm-data)
184 (destructuring-bind (n a b c)
186 (declare (ignore n b))
187 (setf phi1 phi
188 phi (/ (+ phi (asin (* (/ c a) (sin phi)))) 2))))
189 (values (sin phi) (cos phi) (/ (cos phi) (cos (- phi1 phi))))))
191 (defun sn (u m)
192 (cond ((zerop m)
193 ;; jacobi_sn(u,0) = sin(u). Should we use A&S 16.13.1 if m
194 ;; is small enough?
196 ;; sn(u,m) = sin(u) - 1/4*m(u-sin(u)*cos(u))*cos(u)
197 (sin u))
198 ((= m 1)
199 ;; jacobi_sn(u,1) = tanh(u). Should we use A&S 16.15.1 if m
200 ;; is close enough to 1?
202 ;; sn(u,m) = tanh(u) + 1/4*(1-m)*(sinh(u)*cosh(u)-u)*sech(u)^2
203 (tanh u))
205 ;; Use the ascending Landen transformation to compute sn.
206 (let ((s (elliptic-sn-descending u m)))
207 (if (and (realp u) (realp m))
208 (realpart s)
209 s)))))
211 (defun dn (u m)
212 (cond ((zerop m)
213 ;; jacobi_dn(u,0) = 1. Should we use A&S 16.13.3 for small m?
215 ;; dn(u,m) = 1 - 1/2*m*sin(u)^2
217 ((= m 1)
218 ;; jacobi_dn(u,1) = sech(u). Should we use A&S 16.15.3 if m
219 ;; is close enough to 1?
221 ;; dn(u,m) = sech(u) + 1/4*(1-m)*(sinh(u)*cosh(u)+u)*tanh(u)*sech(u)
222 (/ (cosh u)))
224 ;; Use the Gauss transformation from
225 ;; http://functions.wolfram.com/09.29.16.0013.01:
228 ;; dn((1+sqrt(m))*z, 4*sqrt(m)/(1+sqrt(m))^2)
229 ;; = (1-sqrt(m)*sn(z, m)^2)/(1+sqrt(m)*sn(z,m)^2)
231 ;; So
233 ;; dn(y, mu) = (1-sqrt(m)*sn(z, m)^2)/(1+sqrt(m)*sn(z,m)^2)
235 ;; where z = y/(1+sqrt(m)) and mu=4*sqrt(m)/(1+sqrt(m))^2.
237 ;; Solve for m, and we get
239 ;; sqrt(m) = -(mu+2*sqrt(1-mu)-2)/mu or (-mu+2*sqrt(1-mu)+2)/mu.
241 ;; I don't think it matters which sqrt we use, so I (rtoy)
242 ;; arbitrarily choose the first one above.
244 ;; Note that (1-sqrt(1-mu))/(1+sqrt(1-mu)) is the same as
245 ;; -(mu+2*sqrt(1-mu)-2)/mu. Also, the former is more
246 ;; accurate for small mu.
247 (let* ((root (let ((root-1-m (sqrt (- 1 m))))
248 (/ (- 1 root-1-m)
249 (+ 1 root-1-m))))
250 (z (/ u (+ 1 root)))
251 (s (elliptic-sn-descending z (* root root)))
252 (p (* root s s )))
253 (/ (- 1 p)
254 (+ 1 p))))))
256 (defun cn (u m)
257 (cond ((zerop m)
258 ;; jacobi_cn(u,0) = cos(u). Should we use A&S 16.13.2 for
259 ;; small m?
261 ;; cn(u,m) = cos(u) + 1/4*m*(u-sin(u)*cos(u))*sin(u)
262 (cos u))
263 ((= m 1)
264 ;; jacobi_cn(u,1) = sech(u). Should we use A&S 16.15.3 if m
265 ;; is close enough to 1?
267 ;; cn(u,m) = sech(u) - 1/4*(1-m)*(sinh(u)*cosh(u)-u)*tanh(u)*sech(u)
268 (/ (cosh u)))
270 ;; Use the ascending Landen transformation, A&S 16.14.3.
271 (multiple-value-bind (v mu root-mu1)
272 (ascending-transform u m)
273 (let ((d (dn v mu)))
274 (* (/ (+ 1 root-mu1) mu)
275 (/ (- (* d d) root-mu1)
276 d)))))))
278 (in-package :maxima)
281 ;; How this works, I think.
283 ;; $jacobi_sn is the user visible function JACOBI_SN. We put
284 ;; properties on this symbol so maxima can figure out what to do with
285 ;; it.
287 ;; Tell maxima how to simplify the functions $jacobi_sn, etc. This
288 ;; borrows heavily from trigi.lisp.
289 (defprop %jacobi_sn simp-%jacobi_sn operators)
290 (defprop %jacobi_cn simp-%jacobi_cn operators)
291 (defprop %jacobi_dn simp-%jacobi_dn operators)
292 (defprop %inverse_jacobi_sn simp-%inverse_jacobi_sn operators)
293 (defprop %inverse_jacobi_cn simp-%inverse_jacobi_cn operators)
294 (defprop %inverse_jacobi_dn simp-%inverse_jacobi_dn operators)
296 ;; Tell maxima what the derivatives are.
298 ;; Lawden says the derivative wrt to k but that's not what we want.
300 ;; Here's the derivation we used, based on how Lawden get's his results.
302 ;; Let
304 ;; diff(sn(u,m),m) = s
305 ;; diff(cn(u,m),m) = p
306 ;; diff(dn(u,m),m) = q
308 ;; From the derivatives of sn, cn, dn wrt to u, we have
310 ;; diff(sn(u,m),u) = cn(u)*dn(u)
311 ;; diff(cn(u,m),u) = -cn(u)*dn(u)
312 ;; diff(dn(u,m),u) = -m*sn(u)*cn(u)
315 ;; Differentiate these wrt to m:
317 ;; diff(s,u) = p*dn + cn*q
318 ;; diff(p,u) = -p*dn - q*dn
319 ;; diff(q,u) = -sn*cn - m*s*cn - m*sn*q
321 ;; Also recall that
323 ;; sn(u)^2 + cn(u)^2 = 1
324 ;; dn(u)^2 + m*sn(u)^2 = 1
326 ;; Differentiate these wrt to m:
328 ;; sn*s + cn*p = 0
329 ;; 2*dn*q + sn^2 + 2*m*sn*s = 0
331 ;; Thus,
333 ;; p = -s*sn/cn
334 ;; q = -m*s*sn/dn - sn^2/dn/2
336 ;; So
337 ;; diff(s,u) = -s*sn*dn/cn - m*s*sn*cn/dn - sn^2*cn/dn/2
339 ;; or
341 ;; diff(s,u) + s*(sn*dn/cn + m*sn*cn/dn) = -1/2*sn^2*cn/dn
343 ;; diff(s,u) + s*sn/cn/dn*(dn^2 + m*cn^2) = -1/2*sn^2*cn/dn
345 ;; Multiply through by the integrating factor 1/cn/dn:
347 ;; diff(s/cn/dn, u) = -1/2*sn^2/dn^2 = -1/2*sd^2.
349 ;; Interate this to get
351 ;; s/cn/dn = C + -1/2*int sd^2
353 ;; It can be shown that C is zero.
355 ;; We know that (by differentiating this expression)
357 ;; int dn^2 = (1-m)*u+m*sn*cd + m*(1-m)*int sd^2
359 ;; or
361 ;; int sd^2 = 1/m/(1-m)*int dn^2 - u/m - sn*cd/(1-m)
363 ;; Thus, we get
365 ;; s/cn/dn = u/(2*m) + sn*cd/(2*(1-m)) - 1/2/m/(1-m)*int dn^2
367 ;; or
369 ;; s = 1/(2*m)*u*cn*dn + 1/(2*(1-m))*sn*cn^2 - 1/2/(m*(1-m))*cn*dn*E(u)
371 ;; where E(u) = int dn^2 = elliptic_e(am(u)) = elliptic_e(asin(sn(u)))
373 ;; This is our desired result:
375 ;; s = 1/(2*m)*cn*dn*[u - elliptic_e(asin(sn(u)),m)/(1-m)] + sn*cn^2/2/(1-m)
378 ;; Since diff(cn(u,m),m) = p = -s*sn/cn, we have
380 ;; p = -1/(2*m)*sn*dn[u - elliptic_e(asin(sn(u)),m)/(1-m)] - sn^2*cn/2/(1-m)
382 ;; diff(dn(u,m),m) = q = -m*s*sn/dn - sn^2/dn/2
384 ;; q = -1/2*sn*cn*[u-elliptic_e(asin(sn),m)/(1-m)] - m*sn^2*cn^2/dn/2/(1-m)
386 ;; - sn^2/dn/2
388 ;; = -1/2*sn*cn*[u-elliptic_e(asin(sn),m)/(1-m)] + dn*sn^2/2/(m-1)
390 (defprop %jacobi_sn
391 ((u m)
392 ((mtimes) ((%jacobi_cn) u m) ((%jacobi_dn) u m))
393 ((mplus simp)
394 ((mtimes simp) ((rat simp) 1 2)
395 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
396 ((mexpt simp) ((%jacobi_cn simp) u m) 2) ((%jacobi_sn simp) u m))
397 ((mtimes simp) ((rat simp) 1 2) ((mexpt simp) m -1)
398 ((%jacobi_cn simp) u m) ((%jacobi_dn simp) u m)
399 ((mplus simp) u
400 ((mtimes simp) -1 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
401 (($elliptic_e simp) ((%asin simp) ((%jacobi_sn simp) u m)) m))))))
402 grad)
404 (defprop %jacobi_cn
405 ((u m)
406 ((mtimes simp) -1 ((%jacobi_sn simp) u m) ((%jacobi_dn simp) u m))
407 ((mplus simp)
408 ((mtimes simp) ((rat simp) -1 2)
409 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
410 ((%jacobi_cn simp) u m) ((mexpt simp) ((%jacobi_sn simp) u m) 2))
411 ((mtimes simp) ((rat simp) -1 2) ((mexpt simp) m -1)
412 ((%jacobi_dn simp) u m) ((%jacobi_sn simp) u m)
413 ((mplus simp) u
414 ((mtimes simp) -1 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
415 (($elliptic_e simp) ((%asin simp) ((%jacobi_sn simp) u m)) m))))))
416 grad)
418 (defprop %jacobi_dn
419 ((u m)
420 ((mtimes) -1 m ((%jacobi_sn) u m) ((%jacobi_cn) u m))
421 ((mplus simp)
422 ((mtimes simp) ((rat simp) -1 2)
423 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
424 ((%jacobi_dn simp) u m) ((mexpt simp) ((%jacobi_sn simp) u m) 2))
425 ((mtimes simp) ((rat simp) -1 2) ((%jacobi_cn simp) u m)
426 ((%jacobi_sn simp) u m)
427 ((mplus simp) u
428 ((mtimes simp) -1
429 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
430 (($elliptic_e simp) ((%asin simp) ((%jacobi_sn simp) u m)) m))))))
431 grad)
433 ;; The inverse elliptic functions.
435 ;; F(phi|m) = asn(sin(phi),m)
437 ;; so asn(u,m) = F(asin(u)|m)
438 (defprop %inverse_jacobi_sn
439 ((x m)
440 ;; Lawden 3.1.2:
441 ;; inverse_jacobi_sn(x) = integrate(1/sqrt(1-t^2)/sqrt(1-m*t^2),t,0,x)
442 ;; -> 1/sqrt(1-x^2)/sqrt(1-m*x^2)
443 ((mtimes simp)
444 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2)))
445 ((rat simp) -1 2))
446 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m ((mexpt simp) x 2)))
447 ((rat simp) -1 2)))
448 ;; diff(F(asin(u)|m),m)
449 ((mtimes simp) ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
450 ((mplus simp)
451 ((mtimes simp) -1 x
452 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2)))
453 ((rat simp) 1 2))
454 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m ((mexpt simp) x 2)))
455 ((rat simp) -1 2)))
456 ((mtimes simp) ((mexpt simp) m -1)
457 ((mplus simp) (($elliptic_e simp) ((%asin simp) x) m)
458 ((mtimes simp) -1 ((mplus simp) 1 ((mtimes simp) -1 m))
459 (($elliptic_f simp) ((%asin simp) x) m)))))))
460 grad)
462 ;; Let u = inverse_jacobi_cn(x). Then jacobi_cn(u) = x or
463 ;; sqrt(1-jacobi_sn(u)^2) = x. Or
465 ;; jacobi_sn(u) = sqrt(1-x^2)
467 ;; So u = inverse_jacobi_sn(sqrt(1-x^2),m) = inverse_jacob_cn(x,m)
469 (defprop %inverse_jacobi_cn
470 ((x m)
471 ;; Whittaker and Watson, 22.121
472 ;; inverse_jacobi_cn(u,m) = integrate(1/sqrt(1-t^2)/sqrt(1-m+m*t^2), t, u, 1)
473 ;; -> -1/sqrt(1-x^2)/sqrt(1-m+m*x^2)
474 ((mtimes simp) -1
475 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2)))
476 ((rat simp) -1 2))
477 ((mexpt simp)
478 ((mplus simp) 1 ((mtimes simp) -1 m)
479 ((mtimes simp) m ((mexpt simp) x 2)))
480 ((rat simp) -1 2)))
481 ((mtimes simp) ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
482 ((mplus simp)
483 ((mtimes simp) -1
484 ((mexpt simp)
485 ((mplus simp) 1
486 ((mtimes simp) -1 m ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2)))))
487 ((rat simp) -1 2))
488 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2))) ((rat simp) 1 2))
489 ((mabs simp) x))
490 ((mtimes simp) ((mexpt simp) m -1)
491 ((mplus simp)
492 (($elliptic_e simp)
493 ((%asin simp)
494 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2))) ((rat simp) 1 2)))
496 ((mtimes simp) -1 ((mplus simp) 1 ((mtimes simp) -1 m))
497 (($elliptic_f simp)
498 ((%asin simp)
499 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2))) ((rat simp) 1 2)))
500 m)))))))
501 grad)
503 ;; Let u = inverse_jacobi_dn(x). Then
505 ;; jacobi_dn(u) = x or
507 ;; x^2 = jacobi_dn(u)^2 = 1 - m*jacobi_sn(u)^2
509 ;; so jacobi_sn(u) = sqrt(1-x^2)/sqrt(m)
511 ;; or u = inverse_jacobi_sn(sqrt(1-x^2)/sqrt(m))
512 (defprop %inverse_jacobi_dn
513 ((x m)
514 ;; Whittaker and Watson, 22.121
515 ;; inverse_jacobi_dn(u,m) = integrate(1/sqrt(1-t^2)/sqrt(t^2-(1-m)), t, u, 1)
516 ;; -> -1/sqrt(1-x^2)/sqrt(x^2+m-1)
517 ((mtimes simp)
518 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2)))
519 ((rat simp) -1 2))
520 ((mexpt simp) ((mplus simp) -1 m ((mexpt simp) x 2)) ((rat simp) -1 2)))
521 ((mplus simp)
522 ((mtimes simp) ((rat simp) -1 2) ((mexpt simp) m ((rat simp) -3 2))
523 ((mexpt simp)
524 ((mplus simp) 1
525 ((mtimes simp) -1 ((mexpt simp) m -1)
526 ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2)))))
527 ((rat simp) -1 2))
528 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2)))
529 ((rat simp) 1 2))
530 ((mexpt simp) ((mabs simp) x) -1))
531 ((mtimes simp) ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
532 ((mplus simp)
533 ((mtimes simp) -1 ((mexpt simp) m ((rat simp) -1 2))
534 ((mexpt simp)
535 ((mplus simp) 1
536 ((mtimes simp) -1 ((mexpt simp) m -1)
537 ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2)))))
538 ((rat simp) 1 2))
539 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 ((mexpt simp) x 2)))
540 ((rat simp) 1 2))
541 ((mexpt simp) ((mabs simp) x) -1))
542 ((mtimes simp) ((mexpt simp) m -1)
543 ((mplus simp)
544 (($elliptic_e simp)
545 ((%asin simp)
546 ((mtimes simp) ((mexpt simp) m ((rat simp) -1 2))
547 ((mexpt simp) ((mplus simp) 1
548 ((mtimes simp) -1 ((mexpt simp) x 2)))
549 ((rat simp) 1 2))))
551 ((mtimes simp) -1 ((mplus simp) 1 ((mtimes simp) -1 m))
552 (($elliptic_f simp)
553 ((%asin simp)
554 ((mtimes simp) ((mexpt simp) m ((rat simp) -1 2))
555 ((mexpt simp) ((mplus simp) 1
556 ((mtimes simp) -1 ((mexpt simp) x 2)))
557 ((rat simp) 1 2))))
558 m))))))))
559 grad)
562 ;; Define the actual functions for the user
563 (defmfun $jacobi_sn (u m)
564 (simplify (list '(%jacobi_sn) (resimplify u) (resimplify m))))
566 (defmfun $jacobi_cn (u m)
567 (simplify (list '(%jacobi_cn) (resimplify u) (resimplify m))))
569 (defmfun $jacobi_dn (u m)
570 (simplify (list '(%jacobi_dn) (resimplify u) (resimplify m))))
572 (defmfun $inverse_jacobi_sn (u m)
573 (simplify (list '(%inverse_jacobi_sn) (resimplify u) (resimplify m))))
575 (defmfun $inverse_jacobi_cn (u m)
576 (simplify (list '(%inverse_jacobi_cn) (resimplify u) (resimplify m))))
578 (defmfun $inverse_jacobi_dn (u m)
579 (simplify (list '(%inverse_jacobi_dn) (resimplify u) (resimplify m))))
581 ;; Possible forms of a complex number:
583 ;; 2.3
584 ;; $%i
585 ;; ((mplus simp) 2.3 ((mtimes simp) 2.3 $%i))
586 ;; ((mplus simp) 2.3 $%i))
587 ;; ((mtimes simp) 2.3 $%i)
591 ;; Is argument u a complex number with real and imagpart satisfying predicate ntypep?
592 (defun complex-number-p (u &optional (ntypep 'numberp))
593 (let ((R 0) (I 0))
594 (labels ((a1 (x) (cadr x))
595 (a2 (x) (caddr x))
596 (a3+ (x) (cdddr x))
597 (N (x) (funcall ntypep x)) ; N
598 (i (x) (and (eq x '$%i) (N 1))) ; %i
599 (N+i (x) (and (null (a3+ x)) ; mplus test is precondition
600 (N (setq R (a1 x)))
601 (or (and (i (a2 x)) (setq I 1) t)
602 (and (mtimesp (a2 x)) (N*i (a2 x))))))
603 (N*i (x) (and (null (a3+ x)) ; mtimes test is precondition
604 (N (setq I (a1 x)))
605 (eq (a2 x) '$%i))))
606 (declare (inline a1 a2 a3+ N i N+i N*i))
607 (cond ((N u) (values t u 0)) ;2.3
608 ((atom u) (if (i u) (values t 0 1))) ;%i
609 ((mplusp u) (if (N+i u) (values t R I))) ;N+%i, N+N*%i
610 ((mtimesp u) (if (N*i u) (values t R I))) ;N*%i
611 (t nil)))))
613 (defun complexify (x)
614 ;; Convert a Lisp number to a maxima number
615 (cond ((realp x) x)
616 ((complexp x) (add (realpart x) (mul '$%i (imagpart x))))
617 (t (merror (intl:gettext "COMPLEXIFY: argument must be a Lisp real or complex number.~%COMPLEXIFY: found: ~:M") x))))
619 (defun kc-arg (exp m)
620 ;; Replace elliptic_kc(m) in the expression with sym. Check to see
621 ;; if the resulting expression is linear in sym and the constant
622 ;; term is zero. If so, return the coefficient of sym, i.e, the
623 ;; coefficient of elliptic_kc(m).
624 (let* ((sym (gensym))
625 (arg (maxima-substitute sym `((%elliptic_kc) ,m) exp)))
626 (if (and (not (equalp arg exp))
627 (linearp arg sym)
628 (zerop1 (coefficient arg sym 0)))
629 (coefficient arg sym 1)
630 nil)))
632 (defun kc-arg2 (exp m)
633 ;; Replace elliptic_kc(m) in the expression with sym. Check to see
634 ;; if the resulting expression is linear in sym and the constant
635 ;; term is zero. If so, return the coefficient of sym, i.e, the
636 ;; coefficient of elliptic_kc(m), and the constant term. Otherwise,
637 ;; return NIL.
638 (let* ((sym (gensym))
639 (arg (maxima-substitute sym `((%elliptic_kc) ,m) exp)))
640 (if (and (not (equalp arg exp))
641 (linearp arg sym))
642 (list (coefficient arg sym 1)
643 (coefficient arg sym 0))
644 nil)))
646 ;; Tell maxima how to simplify the functions
648 ;; FORM is list containing the actual expression. I don't really know
649 ;; what Y and Z contain. Most of this modeled after SIMP-%SIN.
650 (defun simp-%jacobi_sn (form unused z)
651 (declare (ignore unused))
652 (twoargcheck form)
653 (let ((u (simpcheck (cadr form) z))
654 (m (simpcheck (caddr form) z))
655 coef args)
656 (cond
657 ((float-numerical-eval-p u m)
658 (to (bigfloat::sn (bigfloat:to ($float u)) (bigfloat:to ($float m)))))
659 ((setf args (complex-float-numerical-eval-p u m))
660 (destructuring-bind (u m)
661 args
662 (to (bigfloat::sn (bigfloat:to ($float u)) (bigfloat:to ($float m))))))
663 ((bigfloat-numerical-eval-p u m)
664 (to (bigfloat::sn (bigfloat:to ($bfloat u)) (bigfloat:to ($bfloat m)))))
665 ((setf args (complex-bigfloat-numerical-eval-p u m))
666 (destructuring-bind (u m)
667 args
668 (to (bigfloat::sn (bigfloat:to ($bfloat u)) (bigfloat:to ($bfloat m))))))
669 ((zerop1 u)
670 ;; A&S 16.5.1
672 ((zerop1 m)
673 ;; A&S 16.6.1
674 `((%sin) ,u))
675 ((onep1 m)
676 ;; A&S 16.6.1
677 `((%tanh) ,u))
678 ((and $trigsign (mminusp* u))
679 (neg (cons-exp '%jacobi_sn (neg u) m)))
680 ((and $triginverses
681 (listp u)
682 (member (caar u) '(%inverse_jacobi_sn
683 %inverse_jacobi_ns
684 %inverse_jacobi_cn
685 %inverse_jacobi_nc
686 %inverse_jacobi_dn
687 %inverse_jacobi_nd
688 %inverse_jacobi_sc
689 %inverse_jacobi_cs
690 %inverse_jacobi_sd
691 %inverse_jacobi_ds
692 %inverse_jacobi_cd
693 %inverse_jacobi_dc))
694 (alike1 (third u) m))
695 (let ((inv-arg (second u)))
696 (ecase (caar u)
697 (%inverse_jacobi_sn
698 ;; jacobi_sn(inverse_jacobi_sn(u,m), m) = u
699 inv-arg)
700 (%inverse_jacobi_ns
701 ;; inverse_jacobi_ns(u,m) = inverse_jacobi_sn(1/u,m)
702 (div 1 inv-arg))
703 (%inverse_jacobi_cn
704 ;; sn(x)^2 + cn(x)^2 = 1 so sn(x) = sqrt(1-cn(x)^2)
705 (power (sub 1 (mul inv-arg inv-arg)) 1//2))
706 (%inverse_jacobi_nc
707 ;; inverse_jacobi_nc(u) = inverse_jacobi_cn(1/u)
708 ($jacobi_sn ($inverse_jacobi_cn (div 1 inv-arg) m)
710 (%inverse_jacobi_dn
711 ;; dn(x)^2 + m*sn(x)^2 = 1 so
712 ;; sn(x) = 1/sqrt(m)*sqrt(1-dn(x)^2)
713 (mul (div 1 (power m 1//2))
714 (power (sub 1 (mul inv-arg inv-arg)) 1//2)))
715 (%inverse_jacobi_nd
716 ;; inverse_jacobi_nd(u) = inverse_jacobi_dn(1/u)
717 ($jacobi_sn ($inverse_jacobi_dn (div 1 inv-arg) m)
719 (%inverse_jacobi_sc
720 ;; See below for inverse_jacobi_sc.
721 (div inv-arg (power (add 1 (mul inv-arg inv-arg)) 1//2)))
722 (%inverse_jacobi_cs
723 ;; inverse_jacobi_cs(u) = inverse_jacobi_sc(1/u)
724 ($jacobi_sn ($inverse_jacobi_sc (div 1 inv-arg) m)
726 (%inverse_jacobi_sd
727 ;; See below for inverse_jacobi_sd
728 (div inv-arg (power (add 1 (mul m (mul inv-arg inv-arg))) 1//2)))
729 (%inverse_jacobi_ds
730 ;; inverse_jacobi_ds(u) = inverse_jacobi_sd(1/u)
731 ($jacobi_sn ($inverse_jacobi_sd (div 1 inv-arg) m)
733 (%inverse_jacobi_cd
734 ;; See below
735 (div (power (sub 1 (mul inv-arg inv-arg)) 1//2)
736 (power (sub 1 (mul m (mul inv-arg inv-arg))) 1//2)))
737 (%inverse_jacobi_dc
738 ($jacobi_sn ($inverse_jacobi_cd (div 1 inv-arg) m) m)))))
739 ;; A&S 16.20.1 (Jacobi's Imaginary transformation)
740 ((and $%iargs (multiplep u '$%i))
741 (mul '$%i
742 (cons-exp '%jacobi_sc (coeff u '$%i 1) (add 1 (neg m)))))
743 ((setq coef (kc-arg2 u m))
744 ;; sn(m*K+u)
746 ;; A&S 16.8.1
747 (destructuring-bind (lin const)
748 coef
749 (cond ((integerp lin)
750 (ecase (mod lin 4)
752 ;; sn(4*m*K + u) = sn(u), sn(0) = 0
753 (if (zerop1 const)
755 `((%jacobi_sn simp) ,const ,m)))
757 ;; sn(4*m*K + K + u) = sn(K+u) = cd(u)
758 ;; sn(K) = 1
759 (if (zerop1 const)
761 `((%jacobi_cd simp) ,const ,m)))
763 ;; sn(4*m*K+2*K + u) = sn(2*K+u) = -sn(u)
764 ;; sn(2*K) = 0
765 (if (zerop1 const)
767 (neg `((%jacobi_sn simp) ,const ,m))))
769 ;; sn(4*m*K+3*K+u) = sn(2*K + K + u) = -sn(K+u) = -cd(u)
770 ;; sn(3*K) = -1
771 (if (zerop1 const)
773 (neg `((%jacobi_cd simp) ,const ,m))))))
774 ((and (alike1 lin 1//2)
775 (zerop1 const))
776 ;; A&S 16.5.2
778 ;; sn(1/2*K) = 1/sqrt(1+sqrt(1-m))
779 `((mexpt simp)
780 ((mplus simp) 1
781 ((mexpt simp)
782 ((mplus simp) 1 ((mtimes simp) -1 ,m))
783 ((rat simp) 1 2)))
784 ((rat) -1 2)))
785 ((and (alike1 lin 3//2)
786 (zerop1 const))
787 ;; A&S 16.5.2
789 ;; sn(1/2*K + K) = cd(1/2*K,m)
790 (simplifya
791 `((%jacobi_cd) ((mtimes) ((rat) 1 2) ((%elliptic_kc) ,m))
793 nil))
795 (eqtest (list '(%jacobi_sn) u m) form)))))
797 ;; Nothing to do
798 (eqtest (list '(%jacobi_sn) u m) form)))))
800 (defun simp-%jacobi_cn (form unused z)
801 (declare (ignore unused))
802 (twoargcheck form)
803 (let ((u (simpcheck (cadr form) z))
804 (m (simpcheck (caddr form) z))
805 coef args)
806 (cond
807 ((float-numerical-eval-p u m)
808 (to (bigfloat::cn (bigfloat:to ($float u)) (bigfloat:to ($float m)))))
809 ((setf args (complex-float-numerical-eval-p u m))
810 (destructuring-bind (u m)
811 args
812 (to (bigfloat::cn (bigfloat:to ($float u)) (bigfloat:to ($float m))))))
813 ((bigfloat-numerical-eval-p u m)
814 (to (bigfloat::cn (bigfloat:to ($bfloat u)) (bigfloat:to ($bfloat m)))))
815 ((setf args (complex-bigfloat-numerical-eval-p u m))
816 (destructuring-bind (u m)
817 args
818 (to (bigfloat::cn (bigfloat:to ($bfloat u)) (bigfloat:to ($bfloat m))))))
819 ((zerop1 u)
820 ;; A&S 16.5.1
822 ((zerop1 m)
823 ;; A&S 16.6.2
824 `((%cos) ,u))
825 ((onep1 m)
826 ;; A&S 16.6.2
827 `((%sech) ,u))
828 ((and $trigsign (mminusp* u))
829 (cons-exp '%jacobi_cn (neg u) m))
830 ((and $triginverses
831 (listp u)
832 (member (caar u) '(%inverse_jacobi_sn
833 %inverse_jacobi_ns
834 %inverse_jacobi_cn
835 %inverse_jacobi_nc
836 %inverse_jacobi_dn
837 %inverse_jacobi_nd
838 %inverse_jacobi_sc
839 %inverse_jacobi_cs
840 %inverse_jacobi_sd
841 %inverse_jacobi_ds
842 %inverse_jacobi_cd
843 %inverse_jacobi_dc))
844 (alike1 (third u) m))
845 (cond ((eq (caar u) '%inverse_jacobi_cn)
846 (second u))
848 ;; I'm lazy. Use cn(x) = sqrt(1-sn(x)^2). Hope
849 ;; this is right.
850 (power (sub 1 (power ($jacobi_sn u (third u)) 2))
851 1//2))))
852 ;; A&S 16.20.2 (Jacobi's Imaginary transformation)
853 ((and $%iargs (multiplep u '$%i))
854 (cons-exp '%jacobi_nc (coeff u '$%i 1) (add 1 (neg m))))
855 ((setq coef (kc-arg2 u m))
856 ;; cn(m*K+u)
858 ;; A&S 16.8.2
859 (destructuring-bind (lin const)
860 coef
861 (cond ((integerp lin)
862 (ecase (mod lin 4)
864 ;; cn(4*m*K + u) = cn(u),
865 ;; cn(0) = 1
866 (if (zerop1 const)
868 `((%jacobi_cn simp) ,const ,m)))
870 ;; cn(4*m*K + K + u) = cn(K+u) = -sqrt(m1)*sd(u)
871 ;; cn(K) = 0
872 (if (zerop1 const)
874 (neg `((mtimes simp)
875 ((mexpt simp)
876 ((mplus simp) 1 ((mtimes simp) -1 ,m))
877 ((rat simp) 1 2))
878 ((%jacobi_sd simp) ,const ,m)))))
880 ;; cn(4*m*K + 2*K + u) = cn(2*K+u) = -cn(u)
881 ;; cn(2*K) = -1
882 (if (zerop1 const)
884 (neg `((%jacobi_cn) ,const ,m))))
886 ;; cn(4*m*K + 3*K + u) = cn(2*K + K + u) =
887 ;; -cn(K+u) = sqrt(m1)*sd(u)
889 ;; cn(3*K) = 0
890 (if (zerop1 const)
892 `((mtimes simp)
893 ((mexpt simp)
894 ((mplus simp) 1 ((mtimes simp) -1 ,m))
895 ((rat simp) 1 2))
896 ((%jacobi_sd simp) ,const ,m))))))
897 ((and (alike1 lin 1//2)
898 (zerop1 const))
899 ;; A&S 16.5.2
900 ;; cn(1/2*K) = (1-m)^(1/4)/sqrt(1+sqrt(1-m))
901 `((mtimes simp)
902 ((mexpt simp) ((mplus simp) 1
903 ((mtimes simp) -1 ,m))
904 ((rat simp) 1 4))
905 ((mexpt simp)
906 ((mplus simp) 1
907 ((mexpt simp)
908 ((mplus simp) 1
909 ((mtimes simp) -1 ,m))
910 ((rat simp) 1 2)))
911 ((rat simp) -1 2))))
913 (eqtest (list '(%jacobi_cn) u m) form)))))
915 (eqtest (list '(%jacobi_cn) u m) form)))))
917 (defun simp-%jacobi_dn (form unused z)
918 (declare (ignore unused))
919 (twoargcheck form)
920 (let ((u (simpcheck (cadr form) z))
921 (m (simpcheck (caddr form) z))
922 coef args)
923 (cond
924 ((float-numerical-eval-p u m)
925 (to (bigfloat::dn (bigfloat:to ($float u)) (bigfloat:to ($float m)))))
926 ((setf args (complex-float-numerical-eval-p u m))
927 (destructuring-bind (u m)
928 args
929 (to (bigfloat::dn (bigfloat:to ($float u)) (bigfloat:to ($float m))))))
930 ((bigfloat-numerical-eval-p u m)
931 (to (bigfloat::dn (bigfloat:to ($bfloat u)) (bigfloat:to ($bfloat m)))))
932 ((setf args (complex-bigfloat-numerical-eval-p u m))
933 (destructuring-bind (u m)
934 args
935 (to (bigfloat::dn (bigfloat:to ($bfloat u)) (bigfloat:to ($bfloat m))))))
936 ((zerop1 u)
937 ;; A&S 16.5.1
939 ((zerop1 m)
940 ;; A&S 16.6.3
942 ((onep1 m)
943 ;; A&S 16.6.3
944 (take '(%sech) u))
945 ((and $trigsign (mminusp* u))
946 (cons-exp '%jacobi_dn (neg u) m))
947 ((and $triginverses
948 (listp u)
949 (member (caar u) '(%inverse_jacobi_sn
950 %inverse_jacobi_ns
951 %inverse_jacobi_cn
952 %inverse_jacobi_nc
953 %inverse_jacobi_dn
954 %inverse_jacobi_nd
955 %inverse_jacobi_sc
956 %inverse_jacobi_cs
957 %inverse_jacobi_sd
958 %inverse_jacobi_ds
959 %inverse_jacobi_cd
960 %inverse_jacobi_dc))
961 (alike1 (third u) m))
962 (cond ((eq (caar u) '%inverse_jacobi_dn)
963 ;; jacobi_dn(inverse_jacobi_dn(u,m), m) = u
964 (second u))
966 ;; Express in terms of sn:
967 ;; dn(x) = sqrt(1-m*sn(x)^2)
968 (power (sub 1 (mul m
969 (power ($jacobi_sn u m) 2)))
970 1//2))))
971 ((zerop1 ($ratsimp (sub u (power (sub 1 m) 1//2))))
972 ;; A&S 16.5.3
973 ;; dn(sqrt(1-m),m) = K(m)
974 ($elliptic_kc m))
975 ;; A&S 16.20.2 (Jacobi's Imaginary transformation)
976 ((and $%iargs (multiplep u '$%i))
977 (cons-exp '%jacobi_dc (coeff u '$%i 1)
978 (add 1 (neg m))))
979 ((setq coef (kc-arg2 u m))
980 ;; A&S 16.8.3
982 ;; dn(m*K+u) has period 2K
984 (destructuring-bind (lin const)
985 coef
986 (cond ((integerp lin)
987 (ecase (mod lin 2)
989 ;; dn(2*m*K + u) = dn(u)
990 ;; dn(0) = 1
991 (if (zerop1 const)
993 ;; dn(4*m*K+2*K + u) = dn(2*K+u) = dn(u)
994 `((%jacobi_dn) ,const ,m)))
996 ;; dn(2*m*K + K + u) = dn(K + u) = sqrt(1-m)*nd(u)
997 ;; dn(K) = sqrt(1-m)
998 (if (zerop1 const)
999 `((mexpt simp)
1000 ((mplus simp) 1 ((mtimes simp) -1 ,m))
1001 ((rat simp) 1 2))
1002 `((mtimes simp)
1003 ((mexpt simp)
1004 ((mplus simp) 1 ((mtimes simp) -1 ,m))
1005 ((rat simp) 1 2))
1006 ((%jacobi_nd simp) ,const ,m))))))
1007 ((and (alike1 lin 1//2)
1008 (zerop1 const))
1009 ;; A&S 16.5.2
1010 ;; dn(1/2*K) = (1-m)^(1/4)
1011 `((mexpt simp)
1012 ((mplus simp) 1 ((mtimes simp) -1 ,m))
1013 ((rat simp) 1 4)))
1015 (eqtest (list '(%jacobi_dn) u m) form)))))
1016 (t (eqtest (list '(%jacobi_dn) u m) form)))))
1018 ;; Should we simplify the inverse elliptic functions into the
1019 ;; appropriate incomplete elliptic integral? I think we should leave
1020 ;; it, but perhaps allow some way to do that transformation if
1021 ;; desired.
1023 (defun simp-%inverse_jacobi_sn (form unused z)
1024 (declare (ignore unused))
1025 (twoargcheck form)
1026 (let ((u (simpcheck (cadr form) z))
1027 (m (simpcheck (caddr form) z))
1028 args)
1029 ;; To numerically evaluate inverse_jacobi_sn (asn), use
1031 ;; asn(x,m) = F(asin(x),m)
1033 ;; But F(phi,m) = sin(phi)*rf(cos(phi)^2, 1-m*sin(phi)^2,1). Thus
1035 ;; asn(x,m) = F(asin(x),m)
1036 ;; = x*rf(1-x^2,1-m*x^2,1)
1038 ;; I (rtoy) am not 100% about the first identity above for all
1039 ;; complex values of x and m, but tests seem to indicate that it
1040 ;; produces the correct value as verified by verifying
1041 ;; jacobi_sn(inverse_jacobi_sn(x,m),m) = x.
1042 (cond ((float-numerical-eval-p u m)
1043 (complexify (* u (bigfloat::bf-rf (bigfloat:to (float (- 1 (* u u))))
1044 (bigfloat:to (float (- 1 (* m u u))))
1045 1))))
1046 ((setf args (complex-float-numerical-eval-p u m))
1047 (destructuring-bind (u m)
1048 args
1049 (let ((uu (bigfloat:to ($float u)))
1050 (mm (bigfloat:to ($float m))))
1051 (complexify (* uu (bigfloat::bf-rf (- 1 (* uu uu))
1052 (- 1 (* mm uu uu))
1053 1))))))
1054 ((bigfloat-numerical-eval-p u m)
1055 (let ((uu (bigfloat:to u))
1056 (mm (bigfloat:to m)))
1057 (to (bigfloat:* uu
1058 (bigfloat::bf-rf (bigfloat:- 1 (bigfloat:* uu uu))
1059 (bigfloat:- 1 (bigfloat:* mm uu uu))
1060 1)))))
1061 ((setf args (complex-bigfloat-numerical-eval-p u m))
1062 (destructuring-bind (u m)
1063 args
1064 (let ((uu (bigfloat:to u))
1065 (mm (bigfloat:to m)))
1066 (to (bigfloat:* uu
1067 (bigfloat::bf-rf (bigfloat:- 1 (bigfloat:* uu uu))
1068 (bigfloat:- 1 (bigfloat:* mm uu uu))
1069 1))))))
1070 ((zerop1 u)
1071 ;; asn(0,m) = 0
1073 ((onep1 u)
1074 ;; asn(1,m) = elliptic_kc(m)
1075 ($elliptic_kc m))
1076 ((and (numberp u) (onep1 (- u)))
1077 ;; asn(-1,m) = -elliptic_kc(m)
1078 (mul -1 ($elliptic_kc m)))
1079 ((zerop1 m)
1080 ;; asn(x,0) = F(asin(x),0) = asin(x)
1081 (take '(%asin) u))
1082 ((onep1 m)
1083 ;; asn(x,1) = F(asin(x),1) = log(tan(pi/4+asin(x)/2))
1084 (take '($elliptic_f) (take '(%asin) u) 1))
1085 ((and (eq $triginverses '$all)
1086 (listp u)
1087 (eq (caar u) '%jacobi_sn)
1088 (alike1 (third u) m))
1089 ;; inverse_jacobi_sn(sn(u)) = u
1090 (second u))
1092 ;; Nothing to do
1093 (eqtest (list '(%inverse_jacobi_sn) u m) form)))))
1095 (defun simp-%inverse_jacobi_cn (form unused z)
1096 (declare (ignore unused))
1097 (twoargcheck form)
1098 (let ((u (simpcheck (cadr form) z))
1099 (m (simpcheck (caddr form) z))
1100 args)
1101 (cond ((float-numerical-eval-p u m)
1102 ;; Numerically evaluate acn
1104 ;; acn(x,m) = F(acos(x),m)
1105 (to (elliptic-f (cl:acos ($float u)) ($float m))))
1106 ((setf args (complex-float-numerical-eval-p u m))
1107 (destructuring-bind (u m)
1108 args
1109 (to (elliptic-f (cl:acos (bigfloat:to ($float u)))
1110 (bigfloat:to ($float m))))))
1111 ((bigfloat-numerical-eval-p u m)
1112 (to (bigfloat::bf-elliptic-f (bigfloat:acos (bigfloat:to u))
1113 (bigfloat:to m))))
1114 ((setf args (complex-bigfloat-numerical-eval-p u m))
1115 (destructuring-bind (u m)
1116 args
1117 (to (bigfloat::bf-elliptic-f (bigfloat:acos (bigfloat:to u))
1118 (bigfloat:to m)))))
1119 ((zerop1 m)
1120 ;; asn(x,0) = F(acos(x),0) = acos(x)
1121 `(($elliptic_f) ((%acos) ,u) 0))
1122 ((onep1 m)
1123 ;; asn(x,1) = F(asin(x),1) = log(tan(pi/2+asin(x)/2))
1124 `(($elliptic_f) ((%acos) ,u) 1))
1125 ((zerop1 u)
1126 `((%elliptic_kc) ,m))
1127 ((onep1 u)
1129 ((and (eq $triginverses '$all)
1130 (listp u)
1131 (eq (caar u) '%jacobi_cn)
1132 (alike1 (third u) m))
1133 ;; inverse_jacobi_cn(cn(u)) = u
1134 (second u))
1136 ;; Nothing to do
1137 (eqtest (list '(%inverse_jacobi_cn) u m) form)))))
1139 (defun simp-%inverse_jacobi_dn (form unused z)
1140 (declare (ignore unused))
1141 (twoargcheck form)
1142 (let ((u (simpcheck (cadr form) z))
1143 (m (simpcheck (caddr form) z))
1144 args)
1145 (cond ((float-numerical-eval-p u m)
1146 (to (bigfloat::bf-inverse-jacobi-dn (bigfloat:to (float u))
1147 (bigfloat:to (float m)))))
1148 ((setf args (complex-float-numerical-eval-p u m))
1149 (destructuring-bind (u m)
1150 args
1151 (let ((uu (bigfloat:to ($float u)))
1152 (mm (bigfloat:to ($float m))))
1153 (to (bigfloat::bf-inverse-jacobi-dn uu mm)))))
1154 ((bigfloat-numerical-eval-p u m)
1155 (let ((uu (bigfloat:to u))
1156 (mm (bigfloat:to m)))
1157 (to (bigfloat::bf-inverse-jacobi-dn uu mm))))
1158 ((setf args (complex-bigfloat-numerical-eval-p u m))
1159 (destructuring-bind (u m)
1160 args
1161 (to (bigfloat::bf-inverse-jacobi-dn (bigfloat:to u) (bigfloat:to m)))))
1162 ((onep1 m)
1163 ;; x = dn(u,1) = sech(u). so u = asech(x)
1164 `((%asech) ,u))
1165 ((onep1 u)
1166 ;; jacobi_dn(0,m) = 1
1168 ((zerop1 ($ratsimp (sub u (power (sub 1 m) 1//2))))
1169 ;; jacobi_dn(K(m),m) = sqrt(1-m) so
1170 ;; inverse_jacobi_dn(sqrt(1-m),m) = K(m)
1171 ($elliptic_kc m))
1172 ((and (eq $triginverses '$all)
1173 (listp u)
1174 (eq (caar u) '%jacobi_dn)
1175 (alike1 (third u) m))
1176 ;; inverse_jacobi_dn(dn(u)) = u
1177 (second u))
1179 ;; Nothing to do
1180 (eqtest (list '(%inverse_jacobi_dn) u m) form)))))
1182 ;;;; Elliptic integrals
1184 (let ((errtol (expt (* 4 flonum-epsilon) 1/6))
1185 (c1 (float 1/24))
1186 (c2 (float 3/44))
1187 (c3 (float 1/14)))
1188 (declare (type flonum errtol c1 c2 c3))
1189 (defun crf (x y z)
1190 "Compute Carlson's incomplete or complete elliptic integral of the
1191 first kind:
1196 RF(x, y, z) = I ----------------------------------- dt
1197 ] SQRT(x + t) SQRT(y + t) SQRT(z + t)
1201 x, y, and z may be complex.
1203 (declare (number x y z))
1204 (let ((x (coerce x '(complex flonum)))
1205 (y (coerce y '(complex flonum)))
1206 (z (coerce z '(complex flonum))))
1207 (declare (type (complex flonum) x y z))
1208 (loop
1209 (let* ((mu (/ (+ x y z) 3))
1210 (x-dev (- 2 (/ (+ mu x) mu)))
1211 (y-dev (- 2 (/ (+ mu y) mu)))
1212 (z-dev (- 2 (/ (+ mu z) mu))))
1213 (when (< (max (abs x-dev) (abs y-dev) (abs z-dev)) errtol)
1214 (let ((e2 (- (* x-dev y-dev) (* z-dev z-dev)))
1215 (e3 (* x-dev y-dev z-dev)))
1216 (return (/ (+ 1
1217 (* e2 (- (* c1 e2)
1218 1/10
1219 (* c2 e3)))
1220 (* c3 e3))
1221 (sqrt mu)))))
1222 (let* ((x-root (sqrt x))
1223 (y-root (sqrt y))
1224 (z-root (sqrt z))
1225 (lam (+ (* x-root (+ y-root z-root)) (* y-root z-root))))
1226 (setf x (* (+ x lam) 1/4))
1227 (setf y (* (+ y lam) 1/4))
1228 (setf z (* (+ z lam) 1/4))))))))
1230 ;; Elliptic integral of the first kind (Legendre's form):
1233 ;; phi
1234 ;; /
1235 ;; [ 1
1236 ;; I ------------------- ds
1237 ;; ] 2
1238 ;; / SQRT(1 - m SIN (s))
1239 ;; 0
1241 (defun elliptic-f (phi-arg m-arg)
1242 (flet ((base (phi-arg m-arg)
1243 (cond ((and (realp m-arg) (realp phi-arg))
1244 (let ((phi (float phi-arg))
1245 (m (float m-arg)))
1246 (cond ((> m 1)
1247 ;; A&S 17.4.15
1249 ;; F(phi|m) = 1/sqrt(m)*F(theta|1/m)
1251 ;; with sin(theta) = sqrt(m)*sin(phi)
1252 (/ (elliptic-f (cl:asin (* (sqrt m) (sin phi))) (/ m))
1253 (sqrt m)))
1254 ((< m 0)
1255 ;; A&S 17.4.17
1256 (let* ((m (- m))
1257 (m+1 (+ 1 m))
1258 (root (sqrt m+1))
1259 (m/m+1 (/ m m+1)))
1260 (- (/ (elliptic-f (float (/ pi 2)) m/m+1)
1261 root)
1262 (/ (elliptic-f (- (float (/ pi 2)) phi) m/m+1)
1263 root))))
1264 ((= m 0)
1265 ;; A&S 17.4.19
1266 phi)
1267 ((= m 1)
1268 ;; A&S 17.4.21
1270 1 ;; F(phi,1) = log(sec(phi)+tan(phi))
1271 ;; = log(tan(pi/4+pi/2))
1272 (log (cl:tan (+ (/ phi 2) (float (/ pi 4))))))
1273 ((minusp phi)
1274 (- (elliptic-f (- phi) m)))
1275 ((> phi pi)
1276 ;; A&S 17.4.3
1277 (multiple-value-bind (s phi-rem)
1278 (truncate phi (float pi))
1279 (+ (* 2 s (elliptic-k m))
1280 (elliptic-f phi-rem m))))
1281 ((<= phi (/ pi 2))
1282 (let ((sin-phi (sin phi))
1283 (cos-phi (cos phi))
1284 (k (sqrt m)))
1285 (* sin-phi
1286 (bigfloat::bf-rf (* cos-phi cos-phi)
1287 (* (- 1 (* k sin-phi))
1288 (+ 1 (* k sin-phi)))
1289 1.0))))
1290 ((< phi pi)
1291 (+ (* 2 (elliptic-k m))
1292 (elliptic-f (- phi (float pi)) m)))
1294 (error "Shouldn't happen! Unhandled case in elliptic-f: ~S ~S~%"
1295 phi-arg m-arg)))))
1297 (let ((phi (coerce phi-arg '(complex flonum)))
1298 (m (coerce m-arg '(complex flonum))))
1299 (let ((sin-phi (sin phi))
1300 (cos-phi (cos phi))
1301 (k (sqrt m)))
1302 (* sin-phi
1303 (crf (* cos-phi cos-phi)
1304 (* (- 1 (* k sin-phi))
1305 (+ 1 (* k sin-phi)))
1306 1.0))))))))
1307 ;; Elliptic F is quasi-periodic wrt to z:
1309 ;; F(z|m) = F(z - pi*round(Re(z)/pi)|m) + 2*round(Re(z)/pi)*K(m)
1310 (let ((period (round (realpart phi-arg) pi)))
1311 (+ (base (- phi-arg (* pi period)) m-arg)
1312 (if (zerop period)
1314 (* 2 period
1315 (bigfloat:to (elliptic-k m-arg))))))))
1317 ;; Complete elliptic integral of the first kind
1318 (defun elliptic-k (m)
1319 (cond ((realp m)
1320 (cond ((< m 0)
1321 ;; A&S 17.4.17
1322 (let* ((m (- m))
1323 (m+1 (+ 1 m))
1324 (root (sqrt m+1))
1325 (m/m+1 (/ m m+1)))
1326 (- (/ (elliptic-k m/m+1)
1327 root)
1328 (/ (elliptic-f 0.0 m/m+1)
1329 root))))
1330 ((= m 0)
1331 ;; A&S 17.4.19
1332 (float (/ pi 2)))
1333 ((= m 1)
1334 (maxima::merror
1335 (intl:gettext "elliptic_kc: elliptic_kc(1) is undefined.")))
1337 (bigfloat::bf-rf 0.0 (- 1 m)
1338 1.0))))
1340 (bigfloat::bf-rf 0.0 (- 1 m)
1341 1.0))))
1343 ;; Elliptic integral of the second kind (Legendre's form):
1346 ;; phi
1347 ;; /
1348 ;; [ 2
1349 ;; I SQRT(1 - m SIN (s)) ds
1350 ;; ]
1351 ;; /
1352 ;; 0
1354 (defun elliptic-e (phi m)
1355 (declare (type flonum phi m))
1356 (flet ((base (phi m)
1357 (cond ((= m 0)
1358 ;; A&S 17.4.23
1359 phi)
1360 ((= m 1)
1361 ;; A&S 17.4.25
1362 (sin phi))
1364 (let* ((sin-phi (sin phi))
1365 (cos-phi (cos phi))
1366 (k (sqrt m))
1367 (y (* (- 1 (* k sin-phi))
1368 (+ 1 (* k sin-phi)))))
1369 (to (- (* sin-phi
1370 (bigfloat::bf-rf (* cos-phi cos-phi) y 1.0))
1371 (* (/ m 3)
1372 (expt sin-phi 3)
1373 (bigfloat::bf-rd (* cos-phi cos-phi) y 1.0)))))))))
1374 ;; Elliptic E is quasi-periodic wrt to phi:
1376 ;; E(z|m) = E(z - %pi*round(Re(z)/%pi)|m) + 2*round(Re(z)/%pi)*E(m)
1377 (let ((period (round (realpart phi) pi)))
1378 (+ (base (- phi (* pi period)) m)
1379 (* 2 period (elliptic-ec m))))))
1381 ;; Complete version
1382 (defun elliptic-ec (m)
1383 (declare (type flonum m))
1384 (cond ((= m 0)
1385 ;; A&S 17.4.23
1386 (float (/ pi 2)))
1387 ((= m 1)
1388 ;; A&S 17.4.25
1389 1.0)
1391 (let* ((k (sqrt m))
1392 (y (* (- 1 k)
1393 (+ 1 k))))
1394 (to (- (bigfloat::bf-rf 0.0 y 1.0)
1395 (* (/ m 3)
1396 (bigfloat::bf-rd 0.0 y 1.0))))))))
1399 ;; Define the elliptic integrals for maxima
1401 ;; We use the definitions given in A&S 17.2.6 and 17.2.8. In particular:
1403 ;; phi
1404 ;; /
1405 ;; [ 1
1406 ;; F(phi|m) = I ------------------- ds
1407 ;; ] 2
1408 ;; / SQRT(1 - m SIN (s))
1409 ;; 0
1411 ;; and
1413 ;; phi
1414 ;; /
1415 ;; [ 2
1416 ;; E(phi|m) = I SQRT(1 - m SIN (s)) ds
1417 ;; ]
1418 ;; /
1419 ;; 0
1421 ;; That is, we do not use the modular angle, alpha, as the second arg;
1422 ;; the parameter m = sin(alpha)^2 is used.
1426 (defprop $elliptic_f simp-$elliptic_f operators)
1427 (defprop $elliptic_e simp-$elliptic_e operators)
1429 ;; The derivative of F(phi|m) wrt to phi is easy. The derivative wrt
1430 ;; to m is harder. Here is a derivation. Hope I got it right.
1432 ;; diff(integrate(1/sqrt(1-m*sin(x)^2),x,0,phi), m);
1434 ;; PHI
1435 ;; / 2
1436 ;; [ SIN (x)
1437 ;; I ------------------ dx
1438 ;; ] 2 3/2
1439 ;; / (1 - m SIN (x))
1440 ;; 0
1441 ;; --------------------------
1442 ;; 2
1445 ;; Now use the following relationship that is easily verified:
1447 ;; 2 2
1448 ;; (1 - m) SIN (x) COS (x) COS(x) SIN(x)
1449 ;; ------------------- = ------------------- - DIFF(-------------------, x)
1450 ;; 2 2 2
1451 ;; SQRT(1 - m SIN (x)) SQRT(1 - m SIN (x)) SQRT(1 - m SIN (x))
1454 ;; Now integrate this to get:
1457 ;; PHI
1458 ;; / 2
1459 ;; [ SIN (x)
1460 ;; (1 - m) I ------------------- dx =
1461 ;; ] 2
1462 ;; / SQRT(1 - m SIN (x))
1463 ;; 0
1466 ;; PHI
1467 ;; / 2
1468 ;; [ COS (x)
1469 ;; + I ------------------- dx
1470 ;; ] 2
1471 ;; / SQRT(1 - m SIN (x))
1472 ;; 0
1473 ;; COS(PHI) SIN(PHI)
1474 ;; - ---------------------
1475 ;; 2
1476 ;; SQRT(1 - m SIN (PHI))
1478 ;; Use the fact that cos(x)^2 = 1 - sin(x)^2 to show that this
1479 ;; integral on the RHS is:
1482 ;; (1 - m) elliptic_F(PHI, m) + elliptic_E(PHI, m)
1483 ;; -------------------------------------------
1484 ;; m
1485 ;; So, finally, we have
1489 ;; d
1490 ;; 2 -- (elliptic_F(PHI, m)) =
1491 ;; dm
1493 ;; elliptic_E(PHI, m) - (1 - m) elliptic_F(PHI, m) COS(PHI) SIN(PHI)
1494 ;; ---------------------------------------------- - ---------------------
1495 ;; m 2
1496 ;; SQRT(1 - m SIN (PHI))
1497 ;; ----------------------------------------------------------------------
1498 ;; 1 - m
1500 (defprop $elliptic_f
1501 ((phi m)
1502 ;; diff wrt phi
1503 ;; 1/sqrt(1-m*sin(phi)^2)
1504 ((mexpt simp)
1505 ((mplus simp) 1 ((mtimes simp) -1 m ((mexpt simp) ((%sin simp) phi) 2)))
1506 ((rat simp) -1 2))
1507 ;; diff wrt m
1508 ((mtimes simp) ((rat simp) 1 2)
1509 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
1510 ((mplus simp)
1511 ((mtimes simp) ((mexpt simp) m -1)
1512 ((mplus simp) (($elliptic_e simp) phi m)
1513 ((mtimes simp) -1 ((mplus simp) 1 ((mtimes simp) -1 m))
1514 (($elliptic_f simp) phi m))))
1515 ((mtimes simp) -1 ((%cos simp) phi) ((%sin simp) phi)
1516 ((mexpt simp)
1517 ((mplus simp) 1
1518 ((mtimes simp) -1 m ((mexpt simp) ((%sin simp) phi) 2)))
1519 ((rat simp) -1 2))))))
1520 grad)
1523 ;; The derivative of E(phi|m) wrt to m is much simpler to derive than F(phi|m).
1525 ;; Take the derivative of the definition to get
1527 ;; PHI
1528 ;; / 2
1529 ;; [ SIN (x)
1530 ;; I ------------------- dx
1531 ;; ] 2
1532 ;; / SQRT(1 - m SIN (x))
1533 ;; 0
1534 ;; - ---------------------------
1535 ;; 2
1537 ;; It is easy to see that
1539 ;; PHI
1540 ;; / 2
1541 ;; [ SIN (x)
1542 ;; elliptic_F(PHI, m) - m I ------------------- dx = elliptic_E(PHI, m)
1543 ;; ] 2
1544 ;; / SQRT(1 - m SIN (x))
1545 ;; 0
1547 ;; So we finally have
1549 ;; d elliptic_E(PHI, m) - elliptic_F(PHI, m)
1550 ;; -- (elliptic_E(PHI, m)) = ---------------------------------------
1551 ;; dm 2 m
1553 (defprop $elliptic_e
1554 ((phi m)
1555 ;; sqrt(1-m*sin(phi)^2)
1556 ((mexpt simp)
1557 ((mplus simp) 1 ((mtimes simp) -1 m ((mexpt simp) ((%sin simp) phi) 2)))
1558 ((rat simp) 1 2))
1559 ;; diff wrt m
1560 ((mtimes simp) ((rat simp) 1 2) ((mexpt simp) m -1)
1561 ((mplus simp) (($elliptic_e simp) phi m)
1562 ((mtimes simp) -1 (($elliptic_f simp) phi m)))))
1563 grad)
1565 (defmfun $elliptic_f (phi m)
1566 (simplify (list '($elliptic_f) (resimplify phi) (resimplify m))))
1567 (defmfun $elliptic_e (phi m)
1568 (simplify (list '($elliptic_e) (resimplify phi) (resimplify m))))
1570 (defun simp-$elliptic_f (form unused z)
1571 (declare (ignore unused))
1572 (twoargcheck form)
1573 (let ((phi (simpcheck (cadr form) z))
1574 (m (simpcheck (caddr form) z))
1575 args)
1576 (cond ((float-numerical-eval-p phi m)
1577 ;; Numerically evaluate it
1578 (to (elliptic-f ($float phi) ($float m))))
1579 ((setf args (complex-float-numerical-eval-p phi m))
1580 (destructuring-bind (phi m)
1581 args
1582 (to (elliptic-f (bigfloat:to ($float phi))
1583 (bigfloat:to ($float m))))))
1584 ((bigfloat-numerical-eval-p phi m)
1585 (to (bigfloat::bf-elliptic-f (bigfloat:to ($bfloat phi))
1586 (bigfloat:to ($bfloat m)))))
1587 ((setf args (complex-bigfloat-numerical-eval-p phi m))
1588 (destructuring-bind (phi m)
1589 args
1590 (to (bigfloat::bf-elliptic-f (bigfloat:to ($bfloat phi))
1591 (bigfloat:to ($bfloat m))))))
1592 ((zerop1 phi)
1594 ((zerop1 m)
1595 ;; A&S 17.4.19
1596 phi)
1597 ((onep1 m)
1598 ;; A&S 17.4.21. Let's pick the log tan form. But this
1599 ;; isn't right if we know that abs(phi) > %pi/2, where
1600 ;; elliptic_f is undefined (or infinity).
1601 (cond ((not (eq '$pos (csign (sub ($abs phi) (div '$%pi 2)))))
1602 `((%log) ((%tan)
1603 ((mplus) ((mtimes) $%pi ((rat) 1 4))
1604 ((mtimes) ((rat) 1 2) ,phi)))))
1606 (merror (intl:gettext "elliptic_f: elliptic_f(~:M, ~:M) is undefined.")
1607 phi m))))
1608 ((alike1 phi '((mtimes) ((rat) 1 2) $%pi))
1609 ;; Complete elliptic integral
1610 `((%elliptic_kc) ,m))
1612 ;; Nothing to do
1613 (eqtest (list '($elliptic_f) phi m) form)))))
1615 (defun simp-$elliptic_e (form unused z)
1616 (declare (ignore unused))
1617 (twoargcheck form)
1618 (let ((phi (simpcheck (cadr form) z))
1619 (m (simpcheck (caddr form) z))
1620 args)
1621 (cond ((float-numerical-eval-p phi m)
1622 ;; Numerically evaluate it
1623 (elliptic-e ($float phi) ($float m)))
1624 ((complex-float-numerical-eval-p phi m)
1625 (complexify (bigfloat::bf-elliptic-e (complex ($float ($realpart phi)) ($float ($imagpart phi)))
1626 (complex ($float ($realpart m)) ($float ($imagpart m))))))
1627 ((bigfloat-numerical-eval-p phi m)
1628 (to (bigfloat::bf-elliptic-e (bigfloat:to ($bfloat phi))
1629 (bigfloat:to ($bfloat m)))))
1630 ((setf args (complex-bigfloat-numerical-eval-p phi m))
1631 (destructuring-bind (phi m)
1632 args
1633 (to (bigfloat::bf-elliptic-e (bigfloat:to ($bfloat phi))
1634 (bigfloat:to ($bfloat m))))))
1635 ((zerop1 phi)
1637 ((zerop1 m)
1638 ;; A&S 17.4.23
1639 phi)
1640 ((onep1 m)
1641 ;; A&S 17.4.25, but handle periodicity:
1642 ;; elliptic_e(x,m) = elliptic_e(x-%pi*round(x/%pi), m)
1643 ;; + 2*round(x/%pi)*elliptic_ec(m)
1645 ;; Or
1647 ;; elliptic_e(x,1) = sin(phi) + 2*round(x/%pi)*elliptic_ec(m)
1649 (add (take '(%sin) phi)
1650 (mul 2
1651 (mul (take '(%round) (div phi '$%pi))
1652 (take '(%elliptic_ec) m)))))
1653 ((alike1 phi '((mtimes) ((rat) 1 2) $%pi))
1654 ;; Complete elliptic integral
1655 `((%elliptic_ec) ,m))
1656 ((and ($numberp phi)
1657 (let ((r ($round (div phi '$%pi))))
1658 (and ($numberp r)
1659 (not (zerop1 r)))))
1660 ;; Handle the case where phi is a number where we can apply
1661 ;; the periodicity property without blowing up the
1662 ;; expression.
1663 (add (take '($elliptic_e)
1664 (add phi
1665 (mul (mul -1 '$%pi)
1666 (take '(%round) (div phi '$%pi))))
1668 (mul 2
1669 (mul (take '(%round) (div phi '$%pi))
1670 (take '(%elliptic_ec) m)))))
1672 ;; Nothing to do
1673 (eqtest (list '($elliptic_e) phi m) form)))))
1676 ;; Complete elliptic integrals
1678 ;; elliptic_kc(m) = elliptic_f(%pi/2, m)
1680 ;; elliptic_ec(m) = elliptic_e(%pi/2, m)
1682 (defmfun $elliptic_kc (m)
1683 (simplify (list '(%elliptic_kc) (resimplify m))))
1684 (defmfun $elliptic_ec (m)
1685 (simplify (list '(%elliptic_ec) (resimplify m))))
1688 (defprop %elliptic_kc simp-%elliptic_kc operators)
1689 (defprop %elliptic_ec simp-%elliptic_ec operators)
1691 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1693 ;;; We support a simplim%function. The function is looked up in simplimit and
1694 ;;; handles specific values of the function.
1696 (defprop %elliptic_kc simplim%elliptic_kc simplim%function)
1698 (defun simplim%elliptic_kc (expr var val)
1699 ;; Look for the limit of the argument
1700 (let ((m (limit (cadr expr) var val 'think)))
1701 (cond ((onep1 m)
1702 ;; For an argument 1 return $infinity.
1703 '$infinity)
1705 ;; All other cases are handled by the simplifier of the function.
1706 (simplify (list '(%elliptic_kc) m))))))
1708 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1710 (defun simp-%elliptic_kc (form yy z)
1711 (declare (ignore yy))
1712 (oneargcheck form)
1713 (let ((m (simpcheck (cadr form) z))
1714 args)
1715 (cond ((onep1 m)
1716 ;; elliptic_kc(1) is complex infinity. Maxima can not handle
1717 ;; infinities correctly, throw a Maxima error.
1718 (merror
1719 (intl:gettext "elliptic_kc: elliptic_kc(~:M) is undefined.")
1721 ((float-numerical-eval-p m)
1722 ;; Numerically evaluate it
1723 (to (elliptic-k ($float m))))
1724 ((complex-float-numerical-eval-p m)
1725 (complexify (bigfloat::bf-elliptic-k (complex ($float ($realpart m)) ($float ($imagpart m))))))
1726 ((setf args (complex-bigfloat-numerical-eval-p m))
1727 (destructuring-bind (m)
1728 args
1729 (to (bigfloat::bf-elliptic-k (bigfloat:to ($bfloat m))))))
1730 ((zerop1 m)
1731 '((mtimes) ((rat) 1 2) $%pi))
1732 ((alike1 m 1//2)
1733 ;; http://functions.wolfram.com/EllipticIntegrals/EllipticK/03/01/
1735 ;; elliptic_kc(1/2) = 8*%pi^(3/2)/gamma(-1/4)^2
1736 (div (mul 8 (power '$%pi (div 3 2)))
1737 (power (gm (div -1 4)) 2)))
1738 ((eql -1 m)
1739 ;; elliptic_kc(-1) = gamma(1/4)^2/(4*sqrt(2*%pi))
1740 (div (power (gm (div 1 4)) 2)
1741 (mul 4 (power (mul 2 '$%pi) 1//2))))
1742 ((alike1 m (add 17 (mul -12 (power 2 1//2))))
1743 ;; elliptic_kc(17-12*sqrt(2)) = 2*(2+sqrt(2))*%pi^(3/2)/gamma(-1/4)^2
1744 (div (mul 2 (mul (add 2 (power 2 1//2))
1745 (power '$%pi (div 3 2))))
1746 (power (gm (div -1 4)) 2)))
1748 ;; Nothing to do
1749 (eqtest (list '(%elliptic_kc) m) form)))))
1751 (defprop %elliptic_kc
1752 ((m)
1753 ;; diff wrt m
1754 ((mtimes)
1755 ((rat) 1 2)
1756 ((mplus) ((%elliptic_ec) m)
1757 ((mtimes) -1
1758 ((%elliptic_kc) m)
1759 ((mplus) 1 ((mtimes) -1 m))))
1760 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
1761 ((mexpt) m -1)))
1762 grad)
1764 (defun simp-%elliptic_ec (form yy z)
1765 (declare (ignore yy))
1766 (oneargcheck form)
1767 (let ((m (simpcheck (cadr form) z))
1768 args)
1769 (cond ((float-numerical-eval-p m)
1770 ;; Numerically evaluate it
1771 (elliptic-ec ($float m)))
1772 ((setf args (complex-float-numerical-eval-p m))
1773 (destructuring-bind (m)
1774 args
1775 (complexify (bigfloat::bf-elliptic-ec (bigfloat:to ($float m))))))
1776 ((setf args (complex-bigfloat-numerical-eval-p m))
1777 (destructuring-bind (m)
1778 args
1779 (to (bigfloat::bf-elliptic-ec (bigfloat:to ($bfloat m))))))
1780 ;; Some special cases we know about.
1781 ((zerop1 m)
1782 '((mtimes) ((rat) 1 2) $%pi))
1783 ((onep1 m)
1785 ((alike1 m 1//2)
1786 ;; elliptic_ec(1/2). Use the identity
1788 ;; elliptic_ec(z)*elliptic_kc(1-z) - elliptic_kc(z)*elliptic_kc(1-z)
1789 ;; + elliptic_ec(1-z)*elliptic_kc(z) = %pi/2;
1791 ;; Let z = 1/2 to get
1793 ;; %pi^(3/2)*'elliptic_ec(1/2)/gamma(3/4)^2-%pi^3/(4*gamma(3/4)^4) = %pi/2
1795 ;; since we know that elliptic_kc(1/2) = %pi^(3/2)/(2*gamma(3/4)^2). Hence
1797 ;; elliptic_ec(1/2)
1798 ;; = (2*%pi*gamma(3/4)^4+%pi^3)/(4*%pi^(3/2)*gamma(3/4)^2)
1799 ;; = gamma(3/4)^2/(2*sqrt(%pi))+%pi^(3/2)/(4*gamma(3/4)^2)
1801 (add (div (power (take '(%gamma) (div 3 4)) 2)
1802 (mul 2 (power '$%pi 1//2)))
1803 (div (power '$%pi (div 3 2))
1804 (mul 4 (power (take '(%gamma) (div 3 4)) 2)))))
1805 ((zerop1 (add 1 m))
1806 ;; elliptic_ec(-1). Use the identity
1807 ;; http://functions.wolfram.com/08.01.17.0002.01
1810 ;; elliptic_ec(z) = sqrt(1 - z)*elliptic_ec(z/(z-1))
1812 ;; Let z = -1 to get
1814 ;; elliptic_ec(-1) = sqrt(2)*elliptic_ec(1/2)
1816 ;; Should we expand out elliptic_ec(1/2) using the above result?
1817 (mul (power 2 1//2)
1818 (take '($elliptic_ec) 1//2)))
1820 ;; Nothing to do
1821 (eqtest (list '(%elliptic_ec) m) form)))))
1823 (defprop %elliptic_ec
1824 ((m)
1825 ((mtimes) ((rat) 1 2)
1826 ((mplus) ((%elliptic_ec) m)
1827 ((mtimes) -1 ((%elliptic_kc)
1828 m)))
1829 ((mexpt) m -1)))
1830 grad)
1833 ;; Elliptic integral of the third kind:
1835 ;; (A&S 17.2.14)
1837 ;; phi
1838 ;; /
1839 ;; [ 1
1840 ;; PI(n;phi|m) = I ----------------------------------- ds
1841 ;; ] 2 2
1842 ;; / SQRT(1 - m SIN (s)) (1 - n SIN (s))
1843 ;; 0
1845 ;; As with E and F, we do not use the modular angle alpha but the
1846 ;; parameter m = sin(alpha)^2.
1848 (defprop $elliptic_pi simp-$elliptic_pi operators)
1850 (defmfun $elliptic_pi (n phi m)
1851 (simplify (list '($elliptic_pi)
1852 (resimplify n) (resimplify phi) (resimplify m))))
1854 (defun simp-$elliptic_pi (form yy z)
1855 (declare (ignore yy))
1856 ;;(threeargcheck form)
1857 (let ((n (simpcheck (cadr form) z))
1858 (phi (simpcheck (caddr form) z))
1859 (m (simpcheck (cadddr form) z))
1860 args)
1861 (cond
1862 ((float-numerical-eval-p n phi m)
1863 ;; Numerically evaluate it
1864 (elliptic-pi ($float n) ($float phi) ($float m)))
1865 ((setf args (complex-float-numerical-eval-p n phi m))
1866 (destructuring-bind (n phi m)
1867 args
1868 (elliptic-pi (bigfloat:to ($float n))
1869 (bigfloat:to ($float phi))
1870 (bigfloat:to ($float m)))))
1871 ((bigfloat-numerical-eval-p n phi m)
1872 (to (bigfloat::bf-elliptic-pi (bigfloat:to n)
1873 (bigfloat:to phi)
1874 (bigfloat:to m))))
1875 ((setq args (complex-bigfloat-numerical-eval-p n phi m))
1876 (destructuring-bind (n phi m)
1877 args
1878 (to (bigfloat::bf-elliptic-pi (bigfloat:to n)
1879 (bigfloat:to phi)
1880 (bigfloat:to m)))))
1881 ((zerop1 n)
1882 `(($elliptic_f) ,phi ,m))
1883 ((zerop1 m)
1884 ;; 3 cases depending on n < 1, n > 1, or n = 1.
1885 (let ((s (asksign (resimplify `((mplus) -1 ,n)))))
1886 (case s
1887 ($positive
1888 (div (take '(%atanh) (mul (power (add n -1) 1//2)
1889 (take '(%tan) phi)))
1890 (power (add n -1) 1//2)))
1891 ($negative
1892 (div (take '(%atan) (mul (power (sub 1 n) 1//2)
1893 (take '(%tan) phi)))
1894 (power (sub 1 n) 1//2)))
1895 ($zero
1896 (take '(%tan) phi)))))
1898 ;; Nothing to do
1899 (eqtest (list '($elliptic_pi) n phi m) form)))))
1901 ;; Complete elliptic-pi. That is phi = %pi/2. Then
1902 ;; elliptic_pi(n,m)
1903 ;; = Rf(0, 1-m,1) + Rj(0,1-m,1-n)*n/3;
1904 (defun elliptic-pi-complete (n m)
1905 (to (bigfloat:+ (bigfloat::bf-rf 0 (- 1 m) 1)
1906 (bigfloat:* 1/3 n (bigfloat::bf-rj 0 (- 1 m) 1 (- 1 n))))))
1908 ;; To compute elliptic_pi for all z, we use the property
1909 ;; (http://functions.wolfram.com/08.06.16.0002.01)
1911 ;; elliptic_pi(n, z + %pi*k, m)
1912 ;; = 2*k*elliptic_pi(n, %pi/2, m) + elliptic_pi(n, z, m)
1914 ;; So we are left with computing the integral for 0 <= z < %pi. Using
1915 ;; Carlson's formulation produces the wrong values for %pi/2 < z <
1916 ;; %pi. How to do that?
1918 ;; Let
1920 ;; I(a,b) = integrate(1/(1-n*sin(x)^2)/sqrt(1 - m*sin(x)^2), x, a, b)
1922 ;; That is, I(a,b) is the integral for the elliptic_pi function but
1923 ;; with a lower limit of a and an upper limit of b.
1925 ;; Then, we want to compute I(0, z), with %pi <= z < %pi. Let w = z +
1926 ;; %pi/2, 0 <= w < %pi/2. Then
1928 ;; I(0, w+%pi/2) = I(0, %pi/2) + I(%pi/2, w+%pi/2)
1930 ;; To evaluate I(%pi/2, w+%pi/2), use a change of variables:
1932 ;; changevar('integrate(1/(1-n*sin(x)^2)/sqrt(1 - m*sin(x)^2), x, %pi/2, w + %pi/2),
1933 ;; x-%pi+u,u,x)
1935 ;; = integrate(-1/(sqrt(1-m*sin(u)^2)*(1-n*sin(u)^2)),u,%pi/2-w,%pi/2)
1936 ;; = I(%pi/2-w,%pi/2)
1937 ;; = I(0,%pi/2) - I(0,%pi/2-w)
1939 ;; Thus,
1941 ;; I(0,%pi/2+w) = 2*I(0,%pi/2) - I(0,%pi/2-w)
1943 ;; This allows us to compute the general result with 0 <= z < %pi
1945 ;; I(0, k*%pi + z) = 2*k*I(0,%pi/2) + I(0,z);
1947 ;; If 0 <= z < %pi/2, then the we are done. If %pi/2 <= z < %pi, let
1948 ;; z = w+%pi/2. Then
1950 ;; I(0,z) = 2*I(0,%pi/2) - I(0,%pi/2-w)
1952 ;; Or, since w = z-%pi/2:
1954 ;; I(0,z) = 2*I(0,%pi/2) - I(0,%pi-z)
1956 (defun elliptic-pi (n phi m)
1957 ;; elliptic_pi(n, -phi, m) = -elliptic_pi(n, phi, m). That is, it
1958 ;; is an odd function of phi.
1959 (when (minusp (realpart phi))
1960 (return-from elliptic-pi (- (elliptic-pi n (- phi) m))))
1962 ;; Note: Carlson's DRJ has n defined as the negative of the n given
1963 ;; in A&S.
1964 (flet ((base (n phi m)
1965 ;; elliptic_pi(n,phi,m) =
1966 ;; sin(phi)*Rf(cos(phi)^2, 1-m*sin(phi)^2, 1)
1967 ;; - (-n / 3) * sin(phi)^3
1968 ;; * Rj(cos(phi)^2, 1-m*sin(phi)^2, 1, 1-n*sin(phi)^2)
1969 (let* ((nn (- n))
1970 (sin-phi (sin phi))
1971 (cos-phi (cos phi))
1972 (k (sqrt m))
1973 (k2sin (* (- 1 (* k sin-phi))
1974 (+ 1 (* k sin-phi)))))
1975 (- (* sin-phi (bigfloat::bf-rf (expt cos-phi 2) k2sin 1.0))
1976 (* (/ nn 3) (expt sin-phi 3)
1977 (bigfloat::bf-rj (expt cos-phi 2) k2sin 1.0
1978 (- 1 (* n (expt sin-phi 2)))))))))
1979 ;; FIXME: Reducing the arg by pi has significant round-off.
1980 ;; Consider doing something better.
1981 (let* ((cycles (round (realpart phi) pi))
1982 (rem (- phi (* cycles pi))))
1983 (let ((complete (elliptic-pi-complete n m)))
1984 (to (+ (* 2 cycles complete)
1985 (base n rem m)))))))
1987 ;;; Deriviatives from functions.wolfram.com
1988 ;;; http://functions.wolfram.com/EllipticIntegrals/EllipticPi3/20/
1989 (defprop $elliptic_pi
1990 ((n z m)
1991 ;Derivative wrt first argument
1992 ((mtimes) ((rat) 1 2)
1993 ((mexpt) ((mplus) m ((mtimes) -1 n)) -1)
1994 ((mexpt) ((mplus) -1 n) -1)
1995 ((mplus)
1996 ((mtimes) ((mexpt) n -1)
1997 ((mplus) ((mtimes) -1 m) ((mexpt) n 2))
1998 (($elliptic_pi) n z m))
1999 (($elliptic_e) z m)
2000 ((mtimes) ((mplus) m ((mtimes) -1 n)) ((mexpt) n -1)
2001 (($elliptic_f) z m))
2002 ((mtimes) ((rat) -1 2) n
2003 ((mexpt)
2004 ((mplus) 1 ((mtimes) -1 m ((mexpt) ((%sin) z) 2)))
2005 ((rat) 1 2))
2006 ((mexpt)
2007 ((mplus) 1 ((mtimes) -1 n ((mexpt) ((%sin) z) 2)))
2009 ((%sin) ((mtimes) 2 z)))))
2010 ;derivative wrt second argument
2011 ((mtimes)
2012 ((mexpt)
2013 ((mplus) 1 ((mtimes) -1 m ((mexpt) ((%sin) z) 2)))
2014 ((rat) -1 2))
2015 ((mexpt)
2016 ((mplus) 1 ((mtimes) -1 n ((mexpt) ((%sin) z) 2))) -1))
2017 ;Derivative wrt third argument
2018 ((mtimes) ((rat) 1 2)
2019 ((mexpt) ((mplus) ((mtimes) -1 m) n) -1)
2020 ((mplus) (($elliptic_pi) n z m)
2021 ((mtimes) ((mexpt) ((mplus) -1 m) -1)
2022 (($elliptic_e) z m))
2023 ((mtimes) ((rat) -1 2) ((mexpt) ((mplus) -1 m) -1) m
2024 ((mexpt)
2025 ((mplus) 1 ((mtimes) -1 m ((mexpt) ((%sin) z) 2)))
2026 ((rat) -1 2))
2027 ((%sin) ((mtimes) 2 z))))))
2028 grad)
2030 (in-package #-gcl #:bigfloat #+gcl "BIGFLOAT")
2031 ;; Translation of Jim FitzSimons' bigfloat implementation of elliptic
2032 ;; integrals from http://www.getnet.com/~cherry/elliptbf3.mac.
2034 ;; The algorithms are based on B.C. Carlson's "Numerical Computation
2035 ;; of Real or Complex Elliptic Integrals". These are updated to the
2036 ;; algorithms in Journal of Computational and Applied Mathematics 118
2037 ;; (2000) 71-85 "Reduction Theorems for Elliptic Integrands with the
2038 ;; Square Root of two quadritic factors"
2041 ;; NOTE: Despite the names indicating these are for bigfloat numbers,
2042 ;; the algorithms and routines are generic and will work with floats
2043 ;; and bigfloats.
2045 (defun bferrtol (&rest args)
2046 ;; Compute error tolerance as sqrt(2^(-fpprec)). Not sure this is
2047 ;; quite right, but it makes the routines more accurate as fpprec
2048 ;; increases.
2049 (sqrt (reduce #'min (mapcar #'(lambda (x)
2050 (if (rationalp x)
2051 maxima::flonum-epsilon
2052 (epsilon x)))
2053 args))))
2055 ;; rc(x,y) = integrate(1/2*(t+x)^(-1/2)/(t+y), t, 0, inf)
2057 ;; log(x) = (x-1)*rc(((1+x)/2)^2, x), x > 0
2058 ;; asin(x) = x * rc(1-x^2, 1), |x|<= 1
2059 ;; acos(x) = sqrt(1-x^2)*rc(x^2,1), 0 <= x <=1
2060 ;; atan(x) = x * rc(1,1+x^2)
2061 ;; asinh(x) = x * rc(1+x^2,1)
2062 ;; acosh(x) = sqrt(x^2-1) * rc(x^2,1), x >= 1
2063 ;; atanh(x) = x * rc(1,1-x^2), |x|<=1
2065 (defun bf-rc (x y)
2066 (let ((yn y)
2067 xn z w a an pwr4 n epslon lambda sn s)
2068 (cond ((and (zerop (imagpart yn))
2069 (minusp (realpart yn)))
2070 (setf xn (- x y))
2071 (setf yn (- yn))
2072 (setf z yn)
2073 (setf w (sqrt (/ x xn))))
2075 (setf xn x)
2076 (setf z yn)
2077 (setf w 1)))
2078 (setf a (/ (+ xn yn yn) 3))
2079 (setf epslon (/ (abs (- a xn)) (bferrtol x y)))
2080 (setf an a)
2081 (setf pwr4 1)
2082 (setf n 0)
2083 (loop while (> (* epslon pwr4) (abs an))
2085 (setf pwr4 (/ pwr4 4))
2086 (setf lambda (+ (* 2 (sqrt xn) (sqrt yn)) yn))
2087 (setf an (/ (+ an lambda) 4))
2088 (setf xn (/ (+ xn lambda) 4))
2089 (setf yn (/ (+ yn lambda) 4))
2090 (incf n))
2091 ;; c2=3/10,c3=1/7,c4=3/8,c5=9/22,c6=159/208,c7=9/8
2092 (setf sn (/ (* pwr4 (- z a)) an))
2093 (setf s (* sn sn (+ 3/10
2094 (* sn (+ 1/7
2095 (* sn (+ 3/8
2096 (* sn (+ 9/22
2097 (* sn (+ 159/208
2098 (* sn 9/8))))))))))))
2099 (/ (* w (+ 1 s))
2100 (sqrt an))))
2104 ;; rd(x,y,z) = integrate(3/2/sqrt(t+x)/sqrt(t+y)/sqrt(t+z), t, 0, inf)
2106 ;; E(K) = rf(0, 1-K^2, 1) - (K^2/3)*rd(0,1-K^2,1)
2108 ;; B = integrate(s^2/sqrt(1-s^4), s, 0 ,1)
2109 ;; = beta(3/4,1/2)/4
2110 ;; = sqrt(%pi)*gamma(3/4)/gamma(1/4)
2111 ;; = 1/3*rd(0,2,1)
2112 (defun bf-rd (x y z)
2113 (let* ((xn x)
2114 (yn y)
2115 (zn z)
2116 (a (/ (+ xn yn (* 3 zn)) 5))
2117 (epslon (/ (max (abs (- a xn))
2118 (abs (- a yn))
2119 (abs (- a zn)))
2120 (bferrtol x y z)))
2121 (an a)
2122 (sigma 0)
2123 (power4 1)
2124 (n 0)
2125 xnroot ynroot znroot lam)
2126 (loop while (> (* power4 epslon) (abs an))
2128 (setf xnroot (sqrt xn))
2129 (setf ynroot (sqrt yn))
2130 (setf znroot (sqrt zn))
2131 (setf lam (+ (* xnroot ynroot)
2132 (* xnroot znroot)
2133 (* ynroot znroot)))
2134 (setf sigma (+ sigma (/ power4
2135 (* znroot (+ zn lam)))))
2136 (setf power4 (* power4 1/4))
2137 (setf xn (* (+ xn lam) 1/4))
2138 (setf yn (* (+ yn lam) 1/4))
2139 (setf zn (* (+ zn lam) 1/4))
2140 (setf an (* (+ an lam) 1/4))
2141 (incf n))
2142 ;; c1=-3/14,c2=1/6,c3=9/88,c4=9/22,c5=-3/22,c6=-9/52,c7=3/26
2143 (let* ((xndev (/ (* (- a x) power4) an))
2144 (yndev (/ (* (- a y) power4) an))
2145 (zndev (- (* (+ xndev yndev) 1/3)))
2146 (ee2 (- (* xndev yndev) (* 6 zndev zndev)))
2147 (ee3 (* (- (* 3 xndev yndev)
2148 (* 8 zndev zndev))
2149 zndev))
2150 (ee4 (* 3 (- (* xndev yndev) (* zndev zndev)) zndev zndev))
2151 (ee5 (* xndev yndev zndev zndev zndev))
2152 (s (+ 1
2153 (* -3/14 ee2)
2154 (* 1/6 ee3)
2155 (* 9/88 ee2 ee2)
2156 (* -3/22 ee4)
2157 (* -9/52 ee2 ee3)
2158 (* 3/26 ee5)
2159 (* -1/16 ee2 ee2 ee2)
2160 (* 3/10 ee3 ee3)
2161 (* 3/20 ee2 ee4)
2162 (* 45/272 ee2 ee2 ee3)
2163 (* -9/68 (+ (* ee2 ee5) (* ee3 ee4))))))
2164 (+ (* 3 sigma)
2165 (/ (* power4 s)
2166 (expt an 3/2))))))
2168 (defun bf-rf (x y z)
2169 (let* ((xn x)
2170 (yn y)
2171 (zn z)
2172 (a (/ (+ xn yn zn) 3))
2173 (epslon (/ (max (abs (- a xn))
2174 (abs (- a yn))
2175 (abs (- a zn)))
2176 (bferrtol x y z)))
2177 (an a)
2178 (power4 1)
2179 (n 0)
2180 xnroot ynroot znroot lam)
2181 (loop while (> (* power4 epslon) (abs an))
2183 (setf xnroot (sqrt xn))
2184 (setf ynroot (sqrt yn))
2185 (setf znroot (sqrt zn))
2186 (setf lam (+ (* xnroot ynroot)
2187 (* xnroot znroot)
2188 (* ynroot znroot)))
2189 (setf power4 (* power4 1/4))
2190 (setf xn (* (+ xn lam) 1/4))
2191 (setf yn (* (+ yn lam) 1/4))
2192 (setf zn (* (+ zn lam) 1/4))
2193 (setf an (* (+ an lam) 1/4))
2194 (incf n))
2195 ;; c1=-3/14,c2=1/6,c3=9/88,c4=9/22,c5=-3/22,c6=-9/52,c7=3/26
2196 (let* ((xndev (/ (* (- a x) power4) an))
2197 (yndev (/ (* (- a y) power4) an))
2198 (zndev (- (+ xndev yndev)))
2199 (ee2 (- (* xndev yndev) (* 6 zndev zndev)))
2200 (ee3 (* xndev yndev zndev))
2201 (s (+ 1
2202 (* -1/10 ee2)
2203 (* 1/14 ee3)
2204 (* 1/24 ee2 ee2)
2205 (* -3/44 ee2 ee3))))
2206 (/ s (sqrt an)))))
2208 (defun bf-rj1 (x y z p)
2209 (let* ((xn x)
2210 (yn y)
2211 (zn z)
2212 (pn p)
2213 (en (* (- pn xn)
2214 (- pn yn)
2215 (- pn zn)))
2216 (sigma 0)
2217 (power4 1)
2218 (k 0)
2219 (a (/ (+ xn yn zn pn pn) 5))
2220 (epslon (/ (max (abs (- a xn))
2221 (abs (- a yn))
2222 (abs (- a zn))
2223 (abs (- a pn)))
2224 (bferrtol x y z p)))
2225 (an a)
2226 xnroot ynroot znroot pnroot lam dn)
2227 (loop while (> (* power4 epslon) (abs an))
2229 (setf xnroot (sqrt xn))
2230 (setf ynroot (sqrt yn))
2231 (setf znroot (sqrt zn))
2232 (setf pnroot (sqrt pn))
2233 (setf lam (+ (* xnroot ynroot)
2234 (* xnroot znroot)
2235 (* ynroot znroot)))
2236 (setf dn (* (+ pnroot xnroot)
2237 (+ pnroot ynroot)
2238 (+ pnroot znroot)))
2239 (setf sigma (+ sigma
2240 (/ (* power4
2241 (bf-rc 1 (+ 1 (/ en (* dn dn)))))
2242 dn)))
2243 (setf power4 (* power4 1/4))
2244 (setf en (/ en 64))
2245 (setf xn (* (+ xn lam) 1/4))
2246 (setf yn (* (+ yn lam) 1/4))
2247 (setf zn (* (+ zn lam) 1/4))
2248 (setf pn (* (+ pn lam) 1/4))
2249 (setf an (* (+ an lam) 1/4))
2250 (incf k))
2251 (let* ((xndev (/ (* (- a x) power4) an))
2252 (yndev (/ (* (- a y) power4) an))
2253 (zndev (/ (* (- a z) power4) an))
2254 (pndev (* -0.5 (+ xndev yndev zndev)))
2255 (ee2 (+ (* xndev yndev)
2256 (* xndev zndev)
2257 (* yndev zndev)
2258 (* -3 pndev pndev)))
2259 (ee3 (+ (* xndev yndev zndev)
2260 (* 2 ee2 pndev)
2261 (* 4 pndev pndev pndev)))
2262 (ee4 (* (+ (* 2 xndev yndev zndev)
2263 (* ee2 pndev)
2264 (* 3 pndev pndev pndev))
2265 pndev))
2266 (ee5 (* xndev yndev zndev pndev pndev))
2267 (s (+ 1
2268 (* -3/14 ee2)
2269 (* 1/6 ee3)
2270 (* 9/88 ee2 ee2)
2271 (* -3/22 ee4)
2272 (* -9/52 ee2 ee3)
2273 (* 3/26 ee5)
2274 (* -1/16 ee2 ee2 ee2)
2275 (* 3/10 ee3 ee3)
2276 (* 3/20 ee2 ee4)
2277 (* 45/272 ee2 ee2 ee3)
2278 (* -9/68 (+ (* ee2 ee5) (* ee3 ee4))))))
2279 (+ (* 6 sigma)
2280 (/ (* power4 s)
2281 (sqrt (* an an an)))))))
2283 (defun bf-rj (x y z p)
2284 (let* ((xn x)
2285 (yn y)
2286 (zn z)
2287 (qn (- p)))
2288 (cond ((and (and (zerop (imagpart xn)) (>= (realpart xn) 0))
2289 (and (zerop (imagpart yn)) (>= (realpart yn) 0))
2290 (and (zerop (imagpart zn)) (>= (realpart zn) 0))
2291 (and (zerop (imagpart qn)) (> (realpart qn) 0)))
2292 (destructuring-bind (xn yn zn)
2293 (sort (list xn yn zn) #'<)
2294 (let* ((pn (+ yn (* (- zn yn) (/ (- yn xn) (+ yn qn)))))
2295 (s (- (* (- pn yn) (bf-rj1 xn yn zn pn))
2296 (* 3 (bf-rf xn yn zn)))))
2297 (setf s (+ s (* 3 (sqrt (/ (* xn yn zn)
2298 (+ (* xn zn) (* pn qn))))
2299 (bf-rc (+ (* xn zn) (* pn qn)) (* pn qn)))))
2300 (/ s (+ yn qn)))))
2302 (bf-rj1 x y z p)))))
2304 (defun bf-rg (x y z)
2305 (* 0.5
2306 (+ (* z (bf-rf x y z))
2307 (* (- z x)
2308 (- y z)
2309 (bf-rd x y z)
2310 1/3)
2311 (sqrt (/ (* x y) z)))))
2313 ;; elliptic_f(phi,m) = sin(phi)*rf(cos(phi)^2, 1-m*sin(phi)^2,1)
2314 (defun bf-elliptic-f (phi m)
2315 (flet ((base (phi m)
2316 (cond ((= m 1)
2317 ;; F(z|1) = log(tan(z/2+%pi/4))
2318 (log (tan (+ (/ phi 2) (/ (%pi phi) 4)))))
2320 (let ((s (sin phi))
2321 (c (cos phi)))
2322 (* s (bf-rf (* c c) (- 1 (* m s s)) 1)))))))
2323 ;; Handle periodicity (see elliptic-f)
2324 (let* ((bfpi (%pi phi))
2325 (period (round (realpart phi) bfpi)))
2326 (+ (base (- phi (* bfpi period)) m)
2327 (if (zerop period)
2329 (* 2 period (bf-elliptic-k m)))))))
2331 ;; elliptic_kc(k) = rf(0, 1-k^2,1)
2333 ;; or
2334 ;; elliptic_kc(m) = rf(0, 1-m,1)
2336 (defun bf-elliptic-k (m)
2337 (cond ((= m 0)
2338 (if (maxima::$bfloatp m)
2339 (maxima::$bfloat (maxima::div 'maxima::$%pi 2))
2340 (float (/ pi 2) 1e0)))
2341 ((= m 1)
2342 (maxima::merror
2343 (intl:gettext "elliptic_kc: elliptic_kc(1) is undefined.")))
2345 (bf-rf 0 (- 1 m) 1))))
2347 ;; elliptic_e(phi, k) = sin(phi)*rf(cos(phi)^2,1-k^2*sin(phi)^2,1)
2348 ;; - (k^2/3)*sin(phi)^3*rd(cos(phi)^2, 1-k^2*sin(phi)^2,1)
2351 ;; or
2352 ;; elliptic_e(phi, m) = sin(phi)*rf(cos(phi)^2,1-m*sin(phi)^2,1)
2353 ;; - (m/3)*sin(phi)^3*rd(cos(phi)^2, 1-m*sin(phi)^2,1)
2355 (defun bf-elliptic-e (phi m)
2356 (flet ((base (phi m)
2357 (let* ((s (sin phi))
2358 (c (cos phi))
2359 (c2 (* c c))
2360 (s2 (- 1 (* m s s))))
2361 (- (* s (bf-rf c2 s2 1))
2362 (* (/ m 3) (* s s s) (bf-rd c2 s2 1))))))
2363 ;; Elliptic E is quasi-periodic wrt to phi:
2365 ;; E(z|m) = E(z - %pi*round(Re(z)/%pi)|m) + 2*round(Re(z)/%pi)*E(m)
2366 (let* ((bfpi (%pi phi))
2367 (period (round (realpart phi) bfpi)))
2368 (+ (base (- phi (* bfpi period)) m)
2369 (* 2 period (bf-elliptic-ec m))))))
2372 ;; elliptic_ec(k) = rf(0,1-k^2,1) - (k^2/3)*rd(0,1-k^2,1);
2374 ;; or
2375 ;; elliptic_ec(m) = rf(0,1-m,1) - (m/3)*rd(0,1-m,1);
2377 (defun bf-elliptic-ec (m)
2378 (cond ((= m 0)
2379 (if (typep m 'bigfloat)
2380 (bigfloat (maxima::$bfloat (maxima::div 'maxima::$%pi 2)))
2381 (float (/ pi 2) 1e0)))
2382 ((= m 1)
2383 (if (typep m 'bigfloat)
2384 (bigfloat 1)
2385 1e0))
2387 (let ((m1 (- 1 m)))
2388 (- (bf-rf 0 m1 1)
2389 (* m 1/3 (bf-rd 0 m1 1)))))))
2391 (defun bf-elliptic-pi-complete (n m)
2392 (+ (bf-rf 0 (- 1 m) 1)
2393 (* 1/3 n (bf-rj 0 (- 1 m) 1 (- 1 n)))))
2395 (defun bf-elliptic-pi (n phi m)
2396 ;; Note: Carlson's DRJ has n defined as the negative of the n given
2397 ;; in A&S.
2398 (flet ((base (n phi m)
2399 (let* ((nn (- n))
2400 (sin-phi (sin phi))
2401 (cos-phi (cos phi))
2402 (k (sqrt m))
2403 (k2sin (* (- 1 (* k sin-phi))
2404 (+ 1 (* k sin-phi)))))
2405 (- (* sin-phi (bf-rf (expt cos-phi 2) k2sin 1.0))
2406 (* (/ nn 3) (expt sin-phi 3)
2407 (bf-rj (expt cos-phi 2) k2sin 1.0
2408 (- 1 (* n (expt sin-phi 2)))))))))
2409 ;; FIXME: Reducing the arg by pi has significant round-off.
2410 ;; Consider doing something better.
2411 (let* ((bf-pi (%pi (realpart phi)))
2412 (cycles (round (realpart phi) bf-pi))
2413 (rem (- phi (* cycles bf-pi))))
2414 (let ((complete (bf-elliptic-pi-complete n m)))
2415 (+ (* 2 cycles complete)
2416 (base n rem m))))))
2418 ;; Compute inverse_jacobi_sn, for float or bigfloat args.
2419 (defun bf-inverse-jacobi-sn (u m)
2420 (* u (bf-rf (- 1 (* u u))
2421 (- 1 (* m u u))
2422 1)))
2424 ;; Compute inverse_jacobi_dn. We use the following identity
2425 ;; from Gradshteyn & Ryzhik, 8.153.6
2427 ;; w = dn(z|m) = cn(sqrt(m)*z, 1/m)
2429 ;; Solve for z to get
2431 ;; z = inverse_jacobi_dn(w,m)
2432 ;; = 1/sqrt(m) * inverse_jacobi_cn(w, 1/m)
2433 (defun bf-inverse-jacobi-dn (w m)
2434 (cond ((= w 1)
2435 (float 0 w))
2436 ((= m 1)
2437 ;; jacobi_dn(x,1) = sech(x) so the inverse is asech(x)
2438 (maxima::take '(maxima::%asech) (maxima::to w)))
2440 ;; We should do something better to make sure that things
2441 ;; that should be real are real.
2442 (/ (to (maxima::take '(maxima::%inverse_jacobi_cn)
2443 (maxima::to w)
2444 (maxima::to (/ m))))
2445 (sqrt m)))))
2447 (in-package :maxima)
2449 ;; Define Carlson's elliptic integrals so we can test their
2450 ;; implementation. We only support bigfloat
2452 (defmfun $carlson_rc (x y)
2453 (to (bigfloat::bf-rc (bigfloat:bigfloat ($bfloat x))
2454 (bigfloat:bigfloat ($bfloat y)))))
2456 (defmfun $carlson_rd (x y z)
2457 (to (bigfloat::bf-rd (bigfloat:bigfloat ($bfloat x))
2458 (bigfloat:bigfloat ($bfloat y))
2459 (bigfloat:bigfloat ($bfloat z)))))
2461 (defmfun $carlson_rf (x y z)
2462 (to (bigfloat::bf-rf (bigfloat:bigfloat ($bfloat x))
2463 (bigfloat:bigfloat ($bfloat y))
2464 (bigfloat:bigfloat ($bfloat z)))))
2466 (defmfun $carlson_rj (x y z p)
2467 (to (bigfloat::bf-rj (bigfloat:bigfloat ($bfloat x))
2468 (bigfloat:bigfloat ($bfloat y))
2469 (bigfloat:bigfloat ($bfloat z))
2470 (bigfloat:bigfloat ($bfloat p)))))
2473 ;;; Other Jacobian elliptic functions
2475 ;; jacobi_ns(u,m) = 1/jacobi_sn(u,m)
2476 (defmfun $jacobi_ns (u m)
2477 (simplify (list '(%jacobi_ns) (resimplify u) (resimplify m))))
2479 (defprop %jacobi_ns simp-%jacobi_ns operators)
2481 (defprop %jacobi_ns
2482 ((u m)
2483 ;; diff wrt u
2484 ((mtimes) -1 ((%jacobi_cn) u m) ((%jacobi_dn) u m)
2485 ((mexpt) ((%jacobi_sn) u m) -2))
2486 ;; diff wrt m
2487 ((mtimes) -1 ((mexpt) ((%jacobi_sn) u m) -2)
2488 ((mplus)
2489 ((mtimes) ((rat) 1 2)
2490 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
2491 ((mexpt) ((%jacobi_cn) u m) 2)
2492 ((%jacobi_sn) u m))
2493 ((mtimes) ((rat) 1 2) ((mexpt) m -1)
2494 ((%jacobi_cn) u m) ((%jacobi_dn) u m)
2495 ((mplus) u
2496 ((mtimes) -1
2497 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
2498 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
2499 m)))))))
2500 grad)
2502 (defun simp-%jacobi_ns (form unused z)
2503 (declare (ignore unused))
2504 (twoargcheck form)
2505 (let ((u (simpcheck (cadr form) z))
2506 (m (simpcheck (caddr form) z))
2507 coef args)
2508 (cond
2509 ((float-numerical-eval-p u m)
2510 (to (bigfloat:/ (bigfloat::sn (bigfloat:to ($float u))
2511 (bigfloat:to ($float m))))))
2512 ((setf args (complex-float-numerical-eval-p u m))
2513 (destructuring-bind (u m)
2514 args
2515 (to (bigfloat:/ (bigfloat::sn (bigfloat:to ($float u))
2516 (bigfloat:to ($float m)))))))
2517 ((bigfloat-numerical-eval-p u m)
2518 (let ((uu (bigfloat:to ($bfloat u)))
2519 (mm (bigfloat:to ($bfloat m))))
2520 (to (bigfloat:/ (bigfloat::sn uu mm)))))
2521 ((setf args (complex-bigfloat-numerical-eval-p u m))
2522 (destructuring-bind (u m)
2523 args
2524 (let ((uu (bigfloat:to ($bfloat u)))
2525 (mm (bigfloat:to ($bfloat m))))
2526 (to (bigfloat:/ (bigfloat::sn uu mm))))))
2527 ((zerop1 m)
2528 ;; A&S 16.6.10
2529 (take '(%csc) u))
2530 ((onep1 m)
2531 ;; A&S 16.6.10
2532 (take '(%coth) u))
2533 ((zerop1 u)
2534 (dbz-err1 'jacobi_ns))
2535 ((and $trigsign (mminusp* u))
2536 ;; ns is odd
2537 (neg (cons-exp '%jacobi_ns (neg u) m)))
2538 ((and $triginverses
2539 (listp u)
2540 (member (caar u) '(%inverse_jacobi_sn
2541 %inverse_jacobi_ns
2542 %inverse_jacobi_cn
2543 %inverse_jacobi_nc
2544 %inverse_jacobi_dn
2545 %inverse_jacobi_nd
2546 %inverse_jacobi_sc
2547 %inverse_jacobi_cs
2548 %inverse_jacobi_sd
2549 %inverse_jacobi_ds
2550 %inverse_jacobi_cd
2551 %inverse_jacobi_dc))
2552 (alike1 (third u) m))
2553 (cond ((eq (caar u) '%inverse_jacobi_ns)
2554 (second u))
2556 ;; Express in terms of sn:
2557 ;; ns(x) = 1/sn(x)
2558 (div 1 ($jacobi_sn u m)))))
2559 ;; A&S 16.20 (Jacobi's Imaginary transformation)
2560 ((and $%iargs (multiplep u '$%i))
2561 ;; ns(i*u) = 1/sn(i*u) = -i/sc(u,m1) = -i*cs(u,m1)
2562 (neg (mul '$%i
2563 (cons-exp '%jacobi_cs (coeff u '$%i 1) (add 1 (neg m))))))
2564 ((setq coef (kc-arg2 u m))
2565 ;; A&S 16.8.10
2567 ;; ns(m*K+u) = 1/sn(m*K+u)
2569 (destructuring-bind (lin const)
2570 coef
2571 (cond ((integerp lin)
2572 (ecase (mod lin 4)
2574 ;; ns(4*m*K+u) = ns(u)
2575 ;; ns(0) = infinity
2576 (if (zerop1 const)
2577 (dbz-err1 'jacobi_ns)
2578 `((%jacobi_ns simp) ,const ,m)))
2580 ;; ns(4*m*K + K + u) = ns(K+u) = dc(u)
2581 ;; ns(K) = 1
2582 (if (zerop1 const)
2584 `((%jacobi_dc simp) ,const ,m)))
2586 ;; ns(4*m*K+2*K + u) = ns(2*K+u) = -ns(u)
2587 ;; ns(2*K) = infinity
2588 (if (zerop1 const)
2589 (dbz-err1 'jacobi_ns)
2590 (neg `((%jacobi_ns simp) ,const ,m))))
2592 ;; ns(4*m*K+3*K+u) = ns(2*K + K + u) = -ns(K+u) = -dc(u)
2593 ;; ns(3*K) = -1
2594 (if (zerop1 const)
2596 (neg `((%jacobi_dc simp) ,const ,m))))))
2597 ((and (alike1 lin 1//2)
2598 (zerop1 const))
2599 `((mexpt) ((%jacobi_sn) ,u ,m) -1))
2601 (eqtest (list '(%jacobi_ns) u m) form)))))
2603 ;; Nothing to do
2604 (eqtest (list '(%jacobi_ns) u m) form)))))
2606 ;; jacobi_nc(u,m) = 1/jacobi_cn(u,m)
2608 (defmfun $jacobi_nc (u m)
2609 (simplify (list '(%jacobi_nc) (resimplify u) (resimplify m))))
2611 (defprop %jacobi_nc simp-%jacobi_nc operators)
2613 (defprop %jacobi_nc
2614 ((u m)
2615 ;; wrt u
2616 ((mtimes) ((mexpt) ((%jacobi_cn) u m) -2)
2617 ((%jacobi_dn) u m) ((%jacobi_sn) u m))
2618 ;; wrt m
2619 ((mtimes) -1 ((mexpt) ((%jacobi_cn) u m) -2)
2620 ((mplus)
2621 ((mtimes) ((rat) -1 2)
2622 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
2623 ((%jacobi_cn) u m) ((mexpt) ((%jacobi_sn) u m) 2))
2624 ((mtimes) ((rat) -1 2) ((mexpt) m -1)
2625 ((%jacobi_dn) u m) ((%jacobi_sn) u m)
2626 ((mplus) u
2627 ((mtimes) -1 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
2628 (($elliptic_e) ((%asin) ((%jacobi_sn) u m)) m)))))))
2629 grad)
2631 (defun simp-%jacobi_nc (form unused z)
2632 (declare (ignore unused))
2633 (twoargcheck form)
2634 (let ((u (simpcheck (cadr form) z))
2635 (m (simpcheck (caddr form) z))
2636 coef args)
2637 (cond
2638 ((float-numerical-eval-p u m)
2639 (to (bigfloat:/ (bigfloat::cn (bigfloat:to ($float u))
2640 (bigfloat:to ($float m))))))
2641 ((setf args (complex-float-numerical-eval-p u m))
2642 (destructuring-bind (u m)
2643 args
2644 (to (bigfloat:/ (bigfloat::cn (bigfloat:to ($float u))
2645 (bigfloat:to ($float m)))))))
2646 ((bigfloat-numerical-eval-p u m)
2647 (let ((uu (bigfloat:to ($bfloat u)))
2648 (mm (bigfloat:to ($bfloat m))))
2649 (to (bigfloat:/ (bigfloat::cn uu mm)))))
2650 ((setf args (complex-bigfloat-numerical-eval-p u m))
2651 (destructuring-bind (u m)
2652 args
2653 (let ((uu (bigfloat:to ($bfloat u)))
2654 (mm (bigfloat:to ($bfloat m))))
2655 (to (bigfloat:/ (bigfloat::cn uu mm))))))
2656 ((zerop1 u)
2658 ((zerop1 m)
2659 ;; A&S 16.6.8
2660 (take '(%sec) u))
2661 ((onep1 m)
2662 ;; A&S 16.6.8
2663 `((%cosh) ,u))
2664 ((and $trigsign (mminusp* u))
2665 ;; nc is even
2666 (cons-exp '%jacobi_nc (neg u) m))
2667 ((and $triginverses
2668 (listp u)
2669 (member (caar u) '(%inverse_jacobi_sn
2670 %inverse_jacobi_ns
2671 %inverse_jacobi_cn
2672 %inverse_jacobi_nc
2673 %inverse_jacobi_dn
2674 %inverse_jacobi_nd
2675 %inverse_jacobi_sc
2676 %inverse_jacobi_cs
2677 %inverse_jacobi_sd
2678 %inverse_jacobi_ds
2679 %inverse_jacobi_cd
2680 %inverse_jacobi_dc))
2681 (alike1 (third u) m))
2682 (cond ((eq (caar u) '%inverse_jacobi_nc)
2683 (second u))
2685 ;; Express in terms of cn:
2686 ;; nc(x) = 1/cn(x)
2687 (div 1 ($jacobi_cn u m)))))
2688 ;; A&S 16.20 (Jacobi's Imaginary transformation)
2689 ((and $%iargs (multiplep u '$%i))
2690 ;; nc(i*u) = 1/cn(i*u) = 1/nc(u,1-m) = cn(u,1-m)
2691 (cons-exp '%jacobi_cn (coeff u '$%i 1) (add 1 (neg m))))
2692 ((setq coef (kc-arg2 u m))
2693 ;; A&S 16.8.8
2695 ;; nc(u) = 1/cn(u)
2697 (destructuring-bind (lin const)
2698 coef
2699 (cond ((integerp lin)
2700 (ecase (mod lin 4)
2702 ;; nc(4*m*K+u) = nc(u)
2703 ;; nc(0) = 1
2704 (if (zerop1 const)
2706 `((%jacobi_nc simp) ,const ,m)))
2708 ;; nc(4*m*K+K+u) = nc(K+u) = -ds(u)/sqrt(1-m)
2709 ;; nc(K) = infinity
2710 (if (zerop1 const)
2711 (dbz-err1 'jacobi_nc)
2712 (neg `((mtimes simp)
2713 ((mexpt simp)
2714 ((mplus simp) 1 ((mtimes simp) -1 ,m))
2715 ((rat simp) -1 2))
2716 ((%jacobi_ds simp) ,const ,m)))))
2718 ;; nc(4*m*K+2*K+u) = nc(2*K+u) = -nc(u)
2719 ;; nc(2*K) = -1
2720 (if (zerop1 const)
2722 (neg `((%jacobi_nc) ,const ,m))))
2724 ;; nc(4*m*K+3*K+u) = nc(3*K+u) = nc(2*K+K+u) =
2725 ;; -nc(K+u) = ds(u)/sqrt(1-m)
2727 ;; nc(3*K) = infinity
2728 (if (zerop1 const)
2729 (dbz-err1 'jacobi_nc)
2730 `((mtimes simp)
2731 ((mexpt simp)
2732 ((mplus simp) 1 ((mtimes simp) -1 ,m))
2733 ((rat simp) -1 2))
2734 ((%jacobi_ds simp) ,const ,m))))))
2735 ((and (alike1 1//2 lin)
2736 (zerop1 const))
2737 `((mexpt) ((%jacobi_cn) ,u ,m) -1))
2739 (eqtest (list '(%jacobi_nc) u m) form)))))
2741 ;; Nothing to do
2742 (eqtest (list '(%jacobi_nc) u m) form)))))
2744 ;; jacobi_nd(u,m) = 1/jacobi_dn(u,m)
2745 (defmfun $jacobi_nd (u m)
2746 (simplify (list '(%jacobi_nd) (resimplify u) (resimplify m))))
2748 (defprop %jacobi_nd simp-%jacobi_nd operators)
2750 (defprop %jacobi_nd
2751 ((u m)
2752 ;; wrt u
2753 ((mtimes) m ((%jacobi_cn) u m)
2754 ((mexpt) ((%jacobi_dn) u m) -2) ((%jacobi_sn) u m))
2755 ;; wrt m
2756 ((mtimes) -1 ((mexpt) ((%jacobi_dn) u m) -2)
2757 ((mplus)
2758 ((mtimes) ((rat) -1 2)
2759 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
2760 ((%jacobi_dn) u m)
2761 ((mexpt) ((%jacobi_sn) u m) 2))
2762 ((mtimes) ((rat) -1 2) ((%jacobi_cn) u m)
2763 ((%jacobi_sn) u m)
2764 ((mplus) u
2765 ((mtimes) -1
2766 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
2767 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
2768 m)))))))
2769 grad)
2771 (defun simp-%jacobi_nd (form unused z)
2772 (declare (ignore unused))
2773 (twoargcheck form)
2774 (let ((u (simpcheck (cadr form) z))
2775 (m (simpcheck (caddr form) z))
2776 coef args)
2777 (cond
2778 ((float-numerical-eval-p u m)
2779 (to (bigfloat:/ (bigfloat::dn (bigfloat:to ($float u))
2780 (bigfloat:to ($float m))))))
2781 ((setf args (complex-float-numerical-eval-p u m))
2782 (destructuring-bind (u m)
2783 args
2784 (to (bigfloat:/ (bigfloat::dn (bigfloat:to ($float u))
2785 (bigfloat:to ($float m)))))))
2786 ((bigfloat-numerical-eval-p u m)
2787 (let ((uu (bigfloat:to ($bfloat u)))
2788 (mm (bigfloat:to ($bfloat m))))
2789 (to (bigfloat:/ (bigfloat::dn uu mm)))))
2790 ((setf args (complex-bigfloat-numerical-eval-p u m))
2791 (destructuring-bind (u m)
2792 args
2793 (let ((uu (bigfloat:to ($bfloat u)))
2794 (mm (bigfloat:to ($bfloat m))))
2795 (to (bigfloat:/ (bigfloat::dn uu mm))))))
2796 ((zerop1 u)
2798 ((zerop1 m)
2799 ;; A&S 16.6.6
2801 ((onep1 m)
2802 ;; A&S 16.6.6
2803 `((%cosh) ,u))
2804 ((and $trigsign (mminusp* u))
2805 ;; nd is even
2806 (cons-exp '%jacobi_nd (neg u) m))
2807 ((and $triginverses
2808 (listp u)
2809 (member (caar u) '(%inverse_jacobi_sn
2810 %inverse_jacobi_ns
2811 %inverse_jacobi_cn
2812 %inverse_jacobi_nc
2813 %inverse_jacobi_dn
2814 %inverse_jacobi_nd
2815 %inverse_jacobi_sc
2816 %inverse_jacobi_cs
2817 %inverse_jacobi_sd
2818 %inverse_jacobi_ds
2819 %inverse_jacobi_cd
2820 %inverse_jacobi_dc))
2821 (alike1 (third u) m))
2822 (cond ((eq (caar u) '%inverse_jacobi_nd)
2823 (second u))
2825 ;; Express in terms of dn:
2826 ;; nd(x) = 1/dn(x)
2827 (div 1 ($jacobi_dn u m)))))
2828 ;; A&S 16.20 (Jacobi's Imaginary transformation)
2829 ((and $%iargs (multiplep u '$%i))
2830 ;; nd(i*u) = 1/dn(i*u) = 1/dc(u,1-m) = cd(u,1-m)
2831 (cons-exp '%jacobi_cd (coeff u '$%i 1) (add 1 (neg m))))
2832 ((setq coef (kc-arg2 u m))
2833 ;; A&S 16.8.6
2835 (destructuring-bind (lin const)
2836 coef
2837 (cond ((integerp lin)
2838 ;; nd has period 2K
2839 (ecase (mod lin 2)
2841 ;; nd(2*m*K+u) = nd(u)
2842 ;; nd(0) = 1
2843 (if (zerop1 const)
2845 `((%jacobi_nd) ,const ,m)))
2847 ;; nd(2*m*K+K+u) = nd(K+u) = dn(u)/sqrt(1-m)
2848 ;; nd(K) = 1/sqrt(1-m)
2849 (if (zerop1 const)
2850 `((mexpt simp)
2851 ((mplus simp) 1 ((mtimes simp) -1 ,m))
2852 ((rat simp) -1 2))
2853 `((mtimes simp)
2854 ((%jacobi_nd simp) ,const ,m)
2855 ((mexpt simp)
2856 ((mplus simp) 1 ((mtimes simp) -1 ,m))
2857 ((rat simp) -1 2)))))))
2859 (eqtest (list '(%jacobi_nd) u m) form)))))
2861 ;; Nothing to do
2862 (eqtest (list '(%jacobi_nd) u m) form)))))
2864 ;; jacobi_sc(u,m) = jacobi_sn/jacobi_cn
2865 (defmfun $jacobi_sc (u m)
2866 (simplify (list '(%jacobi_sc) (resimplify u) (resimplify m))))
2868 (defprop %jacobi_sc simp-%jacobi_sc operators)
2870 (defprop %jacobi_sc
2871 ((u m)
2872 ;; wrt u
2873 ((mtimes) ((mexpt) ((%jacobi_cn) u m) -2)
2874 ((%jacobi_dn) u m))
2875 ;; wrt m
2876 ((mplus)
2877 ((mtimes) ((mexpt) ((%jacobi_cn) u m) -1)
2878 ((mplus)
2879 ((mtimes) ((rat) 1 2)
2880 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
2881 ((mexpt) ((%jacobi_cn) u m) 2)
2882 ((%jacobi_sn) u m))
2883 ((mtimes) ((rat) 1 2) ((mexpt) m -1)
2884 ((%jacobi_cn) u m) ((%jacobi_dn) u m)
2885 ((mplus) u
2886 ((mtimes) -1
2887 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
2888 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
2889 m))))))
2890 ((mtimes) -1 ((mexpt) ((%jacobi_cn) u m) -2)
2891 ((%jacobi_sn) u m)
2892 ((mplus)
2893 ((mtimes) ((rat) -1 2)
2894 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
2895 ((%jacobi_cn) u m)
2896 ((mexpt) ((%jacobi_sn) u m) 2))
2897 ((mtimes) ((rat) -1 2) ((mexpt) m -1)
2898 ((%jacobi_dn) u m) ((%jacobi_sn) u m)
2899 ((mplus) u
2900 ((mtimes) -1
2901 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
2902 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
2903 m))))))))
2904 grad)
2906 (defun simp-%jacobi_sc (form unused z)
2907 (declare (ignore unused))
2908 (twoargcheck form)
2909 (let ((u (simpcheck (cadr form) z))
2910 (m (simpcheck (caddr form) z))
2911 coef args)
2912 (cond
2913 ((float-numerical-eval-p u m)
2914 (let ((fu (bigfloat:to ($float u)))
2915 (fm (bigfloat:to ($float m))))
2916 (to (bigfloat:/ (bigfloat::sn fu fm) (bigfloat::cn fu fm)))))
2917 ((setf args (complex-float-numerical-eval-p u m))
2918 (destructuring-bind (u m)
2919 args
2920 (let ((fu (bigfloat:to ($float u)))
2921 (fm (bigfloat:to ($float m))))
2922 (to (bigfloat:/ (bigfloat::sn fu fm) (bigfloat::cn fu fm))))))
2923 ((bigfloat-numerical-eval-p u m)
2924 (let ((uu (bigfloat:to ($bfloat u)))
2925 (mm (bigfloat:to ($bfloat m))))
2926 (to (bigfloat:/ (bigfloat::sn uu mm)
2927 (bigfloat::cn uu mm)))))
2928 ((setf args (complex-bigfloat-numerical-eval-p u m))
2929 (destructuring-bind (u m)
2930 args
2931 (let ((uu (bigfloat:to ($bfloat u)))
2932 (mm (bigfloat:to ($bfloat m))))
2933 (to (bigfloat:/ (bigfloat::sn uu mm)
2934 (bigfloat::cn uu mm))))))
2935 ((zerop1 u)
2937 ((zerop1 m)
2938 ;; A&S 16.6.9
2939 `((%tan) ,u))
2940 ((onep1 m)
2941 ;; A&S 16.6.9
2942 `((%sinh) ,u))
2943 ((and $trigsign (mminusp* u))
2944 ;; sc is odd
2945 (neg (cons-exp '%jacobi_sc (neg u) m)))
2946 ((and $triginverses
2947 (listp u)
2948 (member (caar u) '(%inverse_jacobi_sn
2949 %inverse_jacobi_ns
2950 %inverse_jacobi_cn
2951 %inverse_jacobi_nc
2952 %inverse_jacobi_dn
2953 %inverse_jacobi_nd
2954 %inverse_jacobi_sc
2955 %inverse_jacobi_cs
2956 %inverse_jacobi_sd
2957 %inverse_jacobi_ds
2958 %inverse_jacobi_cd
2959 %inverse_jacobi_dc))
2960 (alike1 (third u) m))
2961 (cond ((eq (caar u) '%inverse_jacobi_sc)
2962 (second u))
2964 ;; Express in terms of sn and cn
2965 ;; sc(x) = sn(x)/cn(x)
2966 (div ($jacobi_sn u m)
2967 ($jacobi_cn u m)))))
2968 ;; A&S 16.20 (Jacobi's Imaginary transformation)
2969 ((and $%iargs (multiplep u '$%i))
2970 ;; sc(i*u) = sn(i*u)/cn(i*u) = i*sc(u,m1)/nc(u,m1) = i*sn(u,m1)
2971 (mul '$%i
2972 (cons-exp '%jacobi_sn (coeff u '$%i 1) (add 1 (neg m)))))
2973 ((setq coef (kc-arg2 u m))
2974 ;; A&S 16.8.9
2975 ;; sc(2*m*K+u) = sc(u)
2976 (destructuring-bind (lin const)
2977 coef
2978 (cond ((integerp lin)
2979 (ecase (mod lin 2)
2981 ;; sc(2*m*K+ u) = sc(u)
2982 ;; sc(0) = 0
2983 (if (zerop1 const)
2985 `((%jacobi_sc simp) ,const ,m)))
2987 ;; sc(2*m*K + K + u) = sc(K+u)= - cs(u)/sqrt(1-m)
2988 ;; sc(K) = infinity
2989 (if (zerop1 const)
2990 (dbz-err1 'jacobi_sc)
2991 (mul -1
2992 (div (cons-exp '%jacobi_cs const m)
2993 (power (sub 1 m) 1//2)))))))
2994 ((and (alike1 lin 1//2)
2995 (zerop1 const))
2996 ;; From A&S 16.3.3 and 16.5.2:
2997 ;; sc(1/2*K) = 1/(1-m)^(1/4)
2998 (power (sub 1 m) (div -1 4)))
3000 (eqtest (list '(%jacobi_sc) u m) form)))))
3002 ;; Nothing to do
3003 (eqtest (list '(%jacobi_sc) u m) form)))))
3005 ;; jacobi_sd(u,m) = jacobi_sn/jacobi_dn
3006 (defmfun $jacobi_sd (u m)
3007 (simplify (list '(%jacobi_sd) (resimplify u) (resimplify m))))
3009 (defprop %jacobi_sd simp-%jacobi_sd operators)
3011 (defprop %jacobi_sd
3012 ((u m)
3013 ;; wrt u
3014 ((mtimes) ((%jacobi_cn) u m)
3015 ((mexpt) ((%jacobi_dn) u m) -2))
3016 ;; wrt m
3017 ((mplus)
3018 ((mtimes) ((mexpt) ((%jacobi_dn) u m) -1)
3019 ((mplus)
3020 ((mtimes) ((rat) 1 2)
3021 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3022 ((mexpt) ((%jacobi_cn) u m) 2)
3023 ((%jacobi_sn) u m))
3024 ((mtimes) ((rat) 1 2) ((mexpt) m -1)
3025 ((%jacobi_cn) u m) ((%jacobi_dn) u m)
3026 ((mplus) u
3027 ((mtimes) -1
3028 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3029 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
3030 m))))))
3031 ((mtimes) -1 ((mexpt) ((%jacobi_dn) u m) -2)
3032 ((%jacobi_sn) u m)
3033 ((mplus)
3034 ((mtimes) ((rat) -1 2)
3035 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3036 ((%jacobi_dn) u m)
3037 ((mexpt) ((%jacobi_sn) u m) 2))
3038 ((mtimes) ((rat) -1 2) ((%jacobi_cn) u m)
3039 ((%jacobi_sn) u m)
3040 ((mplus) u
3041 ((mtimes) -1
3042 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3043 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
3044 m))))))))
3045 grad)
3047 (defun simp-%jacobi_sd (form unused z)
3048 (declare (ignore unused))
3049 (twoargcheck form)
3050 (let ((u (simpcheck (cadr form) z))
3051 (m (simpcheck (caddr form) z))
3052 coef args)
3053 (cond
3054 ((float-numerical-eval-p u m)
3055 (let ((fu (bigfloat:to ($float u)))
3056 (fm (bigfloat:to ($float m))))
3057 (to (bigfloat:/ (bigfloat::sn fu fm) (bigfloat::dn fu fm)))))
3058 ((setf args (complex-float-numerical-eval-p u m))
3059 (destructuring-bind (u m)
3060 args
3061 (let ((fu (bigfloat:to ($float u)))
3062 (fm (bigfloat:to ($float m))))
3063 (to (bigfloat:/ (bigfloat::sn fu fm) (bigfloat::dn fu fm))))))
3064 ((bigfloat-numerical-eval-p u m)
3065 (let ((uu (bigfloat:to ($bfloat u)))
3066 (mm (bigfloat:to ($bfloat m))))
3067 (to (bigfloat:/ (bigfloat::sn uu mm)
3068 (bigfloat::dn uu mm)))))
3069 ((setf args (complex-bigfloat-numerical-eval-p u m))
3070 (destructuring-bind (u m)
3071 args
3072 (let ((uu (bigfloat:to ($bfloat u)))
3073 (mm (bigfloat:to ($bfloat m))))
3074 (to (bigfloat:/ (bigfloat::sn uu mm)
3075 (bigfloat::dn uu mm))))))
3076 ((zerop1 u)
3078 ((zerop1 m)
3079 ;; A&S 16.6.5
3080 `((%sin) ,u))
3081 ((onep1 m)
3082 ;; A&S 16.6.5
3083 `((%sinh) ,u))
3084 ((and $trigsign (mminusp* u))
3085 ;; sd is odd
3086 (neg (cons-exp '%jacobi_sd (neg u) m)))
3087 ((and $triginverses
3088 (listp u)
3089 (member (caar u) '(%inverse_jacobi_sn
3090 %inverse_jacobi_ns
3091 %inverse_jacobi_cn
3092 %inverse_jacobi_nc
3093 %inverse_jacobi_dn
3094 %inverse_jacobi_nd
3095 %inverse_jacobi_sc
3096 %inverse_jacobi_cs
3097 %inverse_jacobi_sd
3098 %inverse_jacobi_ds
3099 %inverse_jacobi_cd
3100 %inverse_jacobi_dc))
3101 (alike1 (third u) m))
3102 (cond ((eq (caar u) '%inverse_jacobi_sd)
3103 (second u))
3105 ;; Express in terms of sn and dn
3106 (div ($jacobi_sn u m)
3107 ($jacobi_dn u m)))))
3108 ;; A&S 16.20 (Jacobi's Imaginary transformation)
3109 ((and $%iargs (multiplep u '$%i))
3110 ;; sd(i*u) = sn(i*u)/dn(i*u) = i*sc(u,m1)/dc(u,m1) = i*sd(u,m1)
3111 (mul '$%i
3112 (cons-exp '%jacobi_sd (coeff u '$%i 1) (add 1 (neg m)))))
3113 ((setq coef (kc-arg2 u m))
3114 ;; A&S 16.8.5
3115 ;; sd(4*m*K+u) = sd(u)
3116 (destructuring-bind (lin const)
3117 coef
3118 (cond ((integerp lin)
3119 (ecase (mod lin 4)
3121 ;; sd(4*m*K+u) = sd(u)
3122 ;; sd(0) = 0
3123 (if (zerop1 const)
3125 `((%jacobi_sd simp) ,const ,m)))
3127 ;; sd(4*m*K+K+u) = sd(K+u) = cn(u)/sqrt(1-m)
3128 ;; sd(K) = 1/sqrt(m1)
3129 (if (zerop1 const)
3130 `((mexpt) ((mplus) 1 ((mtimes) -1 ,m))
3131 ((rat) -1 2))
3132 `((mtimes simp)
3133 ((mexpt simp)
3134 ((mplus simp) 1 ((mtimes simp) -1 ,m))
3135 ((rat simp) -1 2))
3136 ((%jacobi_cn simp) ,const ,m))))
3138 ;; sd(4*m*K+2*K+u) = sd(2*K+u) = -sd(u)
3139 ;; sd(2*K) = 0
3140 (if (zerop1 const)
3142 (neg `((%jacobi_sd) ,const ,m))))
3144 ;; sd(4*m*K+3*K+u) = sd(3*K+u) = sd(2*K+K+u) =
3145 ;; -sd(K+u) = -cn(u)/sqrt(1-m)
3146 ;; sd(3*K) = -1/sqrt(m1)
3147 (if (zerop1 const)
3148 (neg `((mexpt)
3149 ((mplus simp) 1 ((mtimes simp) -1 ,m))
3150 ((rat) -1 2)))
3151 (neg `((mtimes simp)
3152 ((mexpt simp)
3153 ((mplus simp) 1 ((mtimes simp) -1 ,m))
3154 ((rat simp) -1 2))
3155 ((%jacobi_cn simp) ,const ,m)))))))
3156 ((and (alike1 lin 1//2)
3157 (zerop1 const))
3158 ;; jacobi_sn/jacobi_dn
3159 `((mtimes)
3160 ((%jacobi_sn) ((mtimes) ((rat) 1 2)
3161 ((%elliptic_kc) ,m))
3163 ((mexpt)
3164 ((%jacobi_dn) ((mtimes) ((rat) 1 2)
3165 ((%elliptic_kc) ,m))
3167 -1)))
3169 (eqtest (list '(%jacobi_sd) u m) form)))))
3171 ;; Nothing to do
3172 (eqtest (list '(%jacobi_sd) u m) form)))))
3174 ;; jacobi_cs(u,m) = jacobi_cn/jacobi_sn
3175 (defmfun $jacobi_cs (u m)
3176 (simplify (list '(%jacobi_cs) (resimplify u) (resimplify m))))
3178 (defprop %jacobi_cs simp-%jacobi_cs operators)
3180 (defprop %jacobi_cs
3181 ((u m)
3182 ;; wrt u
3183 ((mtimes) -1 ((%jacobi_dn) u m)
3184 ((mexpt) ((%jacobi_sn) u m) -2))
3185 ;; wrt m
3186 ((mplus)
3187 ((mtimes) -1 ((%jacobi_cn) u m)
3188 ((mexpt) ((%jacobi_sn) u m) -2)
3189 ((mplus)
3190 ((mtimes) ((rat) 1 2)
3191 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3192 ((mexpt) ((%jacobi_cn) u m) 2)
3193 ((%jacobi_sn) u m))
3194 ((mtimes) ((rat) 1 2) ((mexpt) m -1)
3195 ((%jacobi_cn) u m) ((%jacobi_dn) u m)
3196 ((mplus) u
3197 ((mtimes) -1
3198 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3199 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
3200 m))))))
3201 ((mtimes) ((mexpt) ((%jacobi_sn) u m) -1)
3202 ((mplus)
3203 ((mtimes) ((rat) -1 2)
3204 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3205 ((%jacobi_cn) u m)
3206 ((mexpt) ((%jacobi_sn) u m) 2))
3207 ((mtimes) ((rat) -1 2) ((mexpt) m -1)
3208 ((%jacobi_dn) u m) ((%jacobi_sn) u m)
3209 ((mplus) u
3210 ((mtimes) -1
3211 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3212 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
3213 m))))))))
3214 grad)
3216 (defun simp-%jacobi_cs (form unused z)
3217 (declare (ignore unused))
3218 (twoargcheck form)
3219 (let ((u (simpcheck (cadr form) z))
3220 (m (simpcheck (caddr form) z))
3221 coef args)
3222 (cond
3223 ((float-numerical-eval-p u m)
3224 (let ((fu (bigfloat:to ($float u)))
3225 (fm (bigfloat:to ($float m))))
3226 (to (bigfloat:/ (bigfloat::cn fu fm) (bigfloat::sn fu fm)))))
3227 ((setf args (complex-float-numerical-eval-p u m))
3228 (destructuring-bind (u m)
3229 args
3230 (let ((fu (bigfloat:to ($float u)))
3231 (fm (bigfloat:to ($float m))))
3232 (to (bigfloat:/ (bigfloat::cn fu fm) (bigfloat::sn fu fm))))))
3233 ((bigfloat-numerical-eval-p u m)
3234 (let ((uu (bigfloat:to ($bfloat u)))
3235 (mm (bigfloat:to ($bfloat m))))
3236 (to (bigfloat:/ (bigfloat::cn uu mm)
3237 (bigfloat::sn uu mm)))))
3238 ((setf args (complex-bigfloat-numerical-eval-p u m))
3239 (destructuring-bind (u m)
3240 args
3241 (let ((uu (bigfloat:to ($bfloat u)))
3242 (mm (bigfloat:to ($bfloat m))))
3243 (to (bigfloat:/ (bigfloat::cn uu mm)
3244 (bigfloat::sn uu mm))))))
3245 ((zerop1 m)
3246 ;; A&S 16.6.12
3247 (take '(%cot) u))
3248 ((onep1 m)
3249 ;; A&S 16.6.12
3250 (take '(%csch) u))
3251 ((zerop1 u)
3252 (dbz-err1 'jacobi_cs))
3253 ((and $trigsign (mminusp* u))
3254 ;; cs is odd
3255 (neg (cons-exp '%jacobi_cs (neg u) m)))
3256 ((and $triginverses
3257 (listp u)
3258 (member (caar u) '(%inverse_jacobi_sn
3259 %inverse_jacobi_ns
3260 %inverse_jacobi_cn
3261 %inverse_jacobi_nc
3262 %inverse_jacobi_dn
3263 %inverse_jacobi_nd
3264 %inverse_jacobi_sc
3265 %inverse_jacobi_cs
3266 %inverse_jacobi_sd
3267 %inverse_jacobi_ds
3268 %inverse_jacobi_cd
3269 %inverse_jacobi_dc))
3270 (alike1 (third u) m))
3271 (cond ((eq (caar u) '%inverse_jacobi_cs)
3272 (second u))
3274 ;; Express in terms of cn an sn
3275 (div ($jacobi_cn u m)
3276 ($jacobi_sn u m)))))
3277 ;; A&S 16.20 (Jacobi's Imaginary transformation)
3278 ((and $%iargs (multiplep u '$%i))
3279 ;; cs(i*u) = cn(i*u)/sn(i*u) = -i*nc(u,m1)/sc(u,m1) = -i*ns(u,m1)
3280 (neg (mul '$%i
3281 (cons-exp '%jacobi_ns (coeff u '$%i 1) (add 1 (neg m))))))
3282 ((setq coef (kc-arg2 u m))
3283 ;; A&S 16.8.12
3285 ;; cs(2*m*K + u) = cs(u)
3286 (destructuring-bind (lin const)
3287 coef
3288 (cond ((integerp lin)
3289 (ecase (mod lin 2)
3291 ;; cs(2*m*K + u) = cs(u)
3292 ;; cs(0) = infinity
3293 (if (zerop1 const)
3294 (dbz-err1 'jacobi_cs)
3295 `((%jacobi_cs simp) ,const ,m)))
3297 ;; cs(K+u) = -sqrt(1-m)*sc(u)
3298 ;; cs(K) = 0
3299 (if (zerop1 const)
3301 `((mtimes simp) -1
3302 ((mexpt simp)
3303 ((mplus simp) 1 ((mtimes simp) -1 ,m))
3304 ((rat simp) 1 2))
3305 ((%jacobi_sc simp) ,const ,m))))))
3306 ((and (alike1 lin 1//2)
3307 (zerop1 const))
3308 ;; 1/jacobi_sc
3309 `((mexpt)
3310 ((%jacobi_sc) ((mtimes) ((rat) 1 2)
3311 ((%elliptic_kc) ,m)) ,m)
3312 -1))
3314 (eqtest (list '(%jacobi_cs simp) u m) form)))))
3316 ;; Nothing to do
3317 (eqtest (list '(%jacobi_cs simp) u m) form)))))
3319 ;; jacobi_cd(u,m) = jacobi_cn/jacobi_dn
3320 (defmfun $jacobi_cd (u m)
3321 (simplify (list '(%jacobi_cd) (resimplify u) (resimplify m))))
3323 (defprop %jacobi_cd simp-%jacobi_cd operators)
3325 (defprop %jacobi_cd
3326 ((u m)
3327 ;; wrt u
3328 ((mtimes) ((mplus) -1 m)
3329 ((mexpt) ((%jacobi_dn) u m) -2)
3330 ((%jacobi_sn) u m))
3331 ;; wrt m
3332 ((mplus)
3333 ((mtimes) -1 ((%jacobi_cn) u m)
3334 ((mexpt) ((%jacobi_dn) u m) -2)
3335 ((mplus)
3336 ((mtimes) ((rat) -1 2)
3337 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3338 ((%jacobi_dn) u m)
3339 ((mexpt) ((%jacobi_sn) u m) 2))
3340 ((mtimes) ((rat) -1 2) ((%jacobi_cn) u m)
3341 ((%jacobi_sn) u m)
3342 ((mplus) u
3343 ((mtimes) -1
3344 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3345 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
3346 m))))))
3347 ((mtimes) ((mexpt) ((%jacobi_dn) u m) -1)
3348 ((mplus)
3349 ((mtimes) ((rat) -1 2)
3350 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3351 ((%jacobi_cn) u m)
3352 ((mexpt) ((%jacobi_sn) u m) 2))
3353 ((mtimes) ((rat) -1 2) ((mexpt) m -1)
3354 ((%jacobi_dn) u m) ((%jacobi_sn) u m)
3355 ((mplus) u
3356 ((mtimes) -1
3357 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3358 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
3359 m))))))))
3360 grad)
3362 (defun simp-%jacobi_cd (form unused z)
3363 (declare (ignore unused))
3364 (twoargcheck form)
3365 (let ((u (simpcheck (cadr form) z))
3366 (m (simpcheck (caddr form) z))
3367 coef args)
3368 (cond
3369 ((float-numerical-eval-p u m)
3370 (let ((fu (bigfloat:to ($float u)))
3371 (fm (bigfloat:to ($float m))))
3372 (to (bigfloat:/ (bigfloat::cn fu fm) (bigfloat::dn fu fm)))))
3373 ((setf args (complex-float-numerical-eval-p u m))
3374 (destructuring-bind (u m)
3375 args
3376 (let ((fu (bigfloat:to ($float u)))
3377 (fm (bigfloat:to ($float m))))
3378 (to (bigfloat:/ (bigfloat::cn fu fm) (bigfloat::dn fu fm))))))
3379 ((bigfloat-numerical-eval-p u m)
3380 (let ((uu (bigfloat:to ($bfloat u)))
3381 (mm (bigfloat:to ($bfloat m))))
3382 (to (bigfloat:/ (bigfloat::cn uu mm) (bigfloat::dn uu mm)))))
3383 ((setf args (complex-bigfloat-numerical-eval-p u m))
3384 (destructuring-bind (u m)
3385 args
3386 (let ((uu (bigfloat:to ($bfloat u)))
3387 (mm (bigfloat:to ($bfloat m))))
3388 (to (bigfloat:/ (bigfloat::cn uu mm) (bigfloat::dn uu mm))))))
3389 ((zerop1 u)
3391 ((zerop1 m)
3392 ;; A&S 16.6.4
3393 `((%cos) ,u))
3394 ((onep1 m)
3395 ;; A&S 16.6.4
3397 ((and $trigsign (mminusp* u))
3398 ;; cd is even
3399 (cons-exp '%jacobi_cd (neg u) m))
3400 ((and $triginverses
3401 (listp u)
3402 (member (caar u) '(%inverse_jacobi_sn
3403 %inverse_jacobi_ns
3404 %inverse_jacobi_cn
3405 %inverse_jacobi_nc
3406 %inverse_jacobi_dn
3407 %inverse_jacobi_nd
3408 %inverse_jacobi_sc
3409 %inverse_jacobi_cs
3410 %inverse_jacobi_sd
3411 %inverse_jacobi_ds
3412 %inverse_jacobi_cd
3413 %inverse_jacobi_dc))
3414 (alike1 (third u) m))
3415 (cond ((eq (caar u) '%inverse_jacobi_cd)
3416 (second u))
3418 ;; Express in terms of cn and dn
3419 (div ($jacobi_cn u m)
3420 ($jacobi_dn u m)))))
3421 ;; A&S 16.20 (Jacobi's Imaginary transformation)
3422 ((and $%iargs (multiplep u '$%i))
3423 ;; cd(i*u) = cn(i*u)/dn(i*u) = nc(u,m1)/dc(u,m1) = nd(u,m1)
3424 (cons-exp '%jacobi_nd (coeff u '$%i 1) (add 1 (neg m))))
3425 ((setf coef (kc-arg2 u m))
3426 ;; A&S 16.8.4
3428 (destructuring-bind (lin const)
3429 coef
3430 (cond ((integerp lin)
3431 (ecase (mod lin 4)
3433 ;; cd(4*m*K + u) = cd(u)
3434 ;; cd(0) = 1
3435 (if (zerop1 const)
3437 `((%jacobi_cd) ,const ,m)))
3439 ;; cd(4*m*K + K + u) = cd(K+u) = -sn(u)
3440 ;; cd(K) = 0
3441 (if (zerop1 const)
3443 (neg `((%jacobi_sn) ,const ,m))))
3445 ;; cd(4*m*K + 2*K + u) = cd(2*K+u) = -cd(u)
3446 ;; cd(2*K) = -1
3447 (if (zerop1 const)
3449 (neg `((%jacobi_cd) ,const ,m))))
3451 ;; cd(4*m*K + 3*K + u) = cd(2*K + K + u) =
3452 ;; -cd(K+u) = sn(u)
3453 ;; cd(3*K) = 0
3454 (if (zerop1 const)
3456 `((%jacobi_sn) ,const ,m)))))
3457 ((and (alike1 lin 1//2)
3458 (zerop1 const))
3459 ;; jacobi_cn/jacobi_dn
3460 `((mtimes)
3461 ((%jacobi_cn) ((mtimes) ((rat) 1 2)
3462 ((%elliptic_kc) ,m))
3464 ((mexpt)
3465 ((%jacobi_dn) ((mtimes) ((rat) 1 2)
3466 ((%elliptic_kc) ,m))
3468 -1)))
3470 ;; Nothing to do
3471 (eqtest (list '(%jacobi_cd) u m) form)))))
3473 ;; Nothing to do
3474 (eqtest (list '(%jacobi_cd) u m) form)))))
3476 ;; jacobi_ds(u,m) = jacobi_dn/jacobi_sn
3477 (defmfun $jacobi_ds (u m)
3478 (simplify (list '(%jacobi_ds) (resimplify u) (resimplify m))))
3480 (defprop %jacobi_ds simp-%jacobi_ds operators)
3482 (defprop %jacobi_ds
3483 ((u m)
3484 ;; wrt u
3485 ((mtimes) -1 ((%jacobi_cn) u m)
3486 ((mexpt) ((%jacobi_sn) u m) -2))
3487 ;; wrt m
3488 ((mplus)
3489 ((mtimes) -1 ((%jacobi_dn) u m)
3490 ((mexpt) ((%jacobi_sn) u m) -2)
3491 ((mplus)
3492 ((mtimes) ((rat) 1 2)
3493 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3494 ((mexpt) ((%jacobi_cn) u m) 2)
3495 ((%jacobi_sn) u m))
3496 ((mtimes) ((rat) 1 2) ((mexpt) m -1)
3497 ((%jacobi_cn) u m) ((%jacobi_dn) u m)
3498 ((mplus) u
3499 ((mtimes) -1
3500 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3501 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
3502 m))))))
3503 ((mtimes) ((mexpt) ((%jacobi_sn) u m) -1)
3504 ((mplus)
3505 ((mtimes) ((rat) -1 2)
3506 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3507 ((%jacobi_dn) u m)
3508 ((mexpt) ((%jacobi_sn) u m) 2))
3509 ((mtimes) ((rat) -1 2) ((%jacobi_cn) u m)
3510 ((%jacobi_sn) u m)
3511 ((mplus) u
3512 ((mtimes) -1
3513 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3514 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
3515 m))))))))
3516 grad)
3518 (defun simp-%jacobi_ds (form unused z)
3519 (declare (ignore unused))
3520 (twoargcheck form)
3521 (let ((u (simpcheck (cadr form) z))
3522 (m (simpcheck (caddr form) z))
3523 coef args)
3524 (cond
3525 ((float-numerical-eval-p u m)
3526 (let ((fu (bigfloat:to ($float u)))
3527 (fm (bigfloat:to ($float m))))
3528 (to (bigfloat:/ (bigfloat::dn fu fm) (bigfloat::sn fu fm)))))
3529 ((setf args (complex-float-numerical-eval-p u m))
3530 (destructuring-bind (u m)
3531 args
3532 (let ((fu (bigfloat:to ($float u)))
3533 (fm (bigfloat:to ($float m))))
3534 (to (bigfloat:/ (bigfloat::dn fu fm) (bigfloat::sn fu fm))))))
3535 ((bigfloat-numerical-eval-p u m)
3536 (let ((uu (bigfloat:to ($bfloat u)))
3537 (mm (bigfloat:to ($bfloat m))))
3538 (to (bigfloat:/ (bigfloat::dn uu mm)
3539 (bigfloat::sn uu mm)))))
3540 ((setf args (complex-bigfloat-numerical-eval-p u m))
3541 (destructuring-bind (u m)
3542 args
3543 (let ((uu (bigfloat:to ($bfloat u)))
3544 (mm (bigfloat:to ($bfloat m))))
3545 (to (bigfloat:/ (bigfloat::dn uu mm)
3546 (bigfloat::sn uu mm))))))
3547 ((zerop1 m)
3548 ;; A&S 16.6.11
3549 (take '(%csc) u))
3550 ((onep1 m)
3551 ;; A&S 16.6.11
3552 (take '(%csch) u))
3553 ((zerop1 u)
3554 (dbz-err1 'jacobi_ds))
3555 ((and $trigsign (mminusp* u))
3556 (neg (cons-exp '%jacobi_ds (neg u) m)))
3557 ((and $triginverses
3558 (listp u)
3559 (member (caar u) '(%inverse_jacobi_sn
3560 %inverse_jacobi_ns
3561 %inverse_jacobi_cn
3562 %inverse_jacobi_nc
3563 %inverse_jacobi_dn
3564 %inverse_jacobi_nd
3565 %inverse_jacobi_sc
3566 %inverse_jacobi_cs
3567 %inverse_jacobi_sd
3568 %inverse_jacobi_ds
3569 %inverse_jacobi_cd
3570 %inverse_jacobi_dc))
3571 (alike1 (third u) m))
3572 (cond ((eq (caar u) '%inverse_jacobi_ds)
3573 (second u))
3575 ;; Express in terms of dn and sn
3576 (div ($jacobi_dn u m)
3577 ($jacobi_sn u m)))))
3578 ;; A&S 16.20 (Jacobi's Imaginary transformation)
3579 ((and $%iargs (multiplep u '$%i))
3580 ;; ds(i*u) = dn(i*u)/sn(i*u) = -i*dc(u,m1)/sc(u,m1) = -i*ds(u,m1)
3581 (neg (mul '$%i
3582 (cons-exp '%jacobi_ds (coeff u '$%i 1) (add 1 (neg m))))))
3583 ((setf coef (kc-arg2 u m))
3584 ;; A&S 16.8.11
3585 (destructuring-bind (lin const)
3586 coef
3587 (cond ((integerp lin)
3588 (ecase (mod lin 4)
3590 ;; ds(4*m*K + u) = ds(u)
3591 ;; ds(0) = infinity
3592 (if (zerop1 const)
3593 (dbz-err1 'jacobi_ds)
3594 `((%jacobi_ds) ,const ,m)))
3596 ;; ds(4*m*K + K + u) = ds(K+u) = sqrt(1-m)*nc(u)
3597 ;; ds(K) = sqrt(1-m)
3598 (if (zerop1 const)
3599 `((mexpt simp)
3600 ((mplus simp) 1 ((mtimes simp) -1 ,m))
3601 ((rat simp) 1 2))
3602 `((mtimes simp)
3603 ((mexpt simp)
3604 ((mplus simp) 1 ((mtimes simp) -1 ,m))
3605 ((rat simp) 1 2))
3606 ((%jacobi_nc simp) ,const ,m))))
3608 ;; ds(4*m*K + 2*K + u) = ds(2*K+u) = -ds(u)
3609 ;; ds(0) = pole
3610 (if (zerop1 const)
3611 (dbz-err1 'jacobi_ds)
3612 (neg `((%jacobi_ds) ,const ,m))))
3614 ;; ds(4*m*K + 3*K + u) = ds(2*K + K + u) =
3615 ;; -ds(K+u) = -sqrt(1-m)*nc(u)
3616 ;; ds(3*K) = -sqrt(1-m)
3617 (if (zerop1 const)
3618 (neg `((mexpt simp)
3619 ((mplus simp) 1 ((mtimes simp) -1 ,m))
3620 ((rat simp) 1 2)))
3621 (neg `((mtimes simp)
3622 ((mexpt simp)
3623 ((mplus simp) 1 ((mtimes simp) -1 ,m))
3624 ((rat simp) 1 2))
3625 ((%jacobi_nc simp) ,const ,m)))))))
3626 ((and (alike1 lin 1//2)
3627 (zerop1 const))
3628 ;; jacobi_dn/jacobi_sn
3629 `((mtimes)
3630 ((%jacobi_dn) ((mtimes) ((rat) 1 2)
3631 ((%elliptic_kc) ,m))
3633 ((mexpt)
3634 ((%jacobi_sn) ((mtimes) ((rat) 1 2)
3635 ((%elliptic_kc) ,m))
3637 -1)))
3639 ;; Nothing to do
3640 (eqtest (list '(%jacobi_ds) u m) form)))))
3642 ;; Nothing to do
3643 (eqtest (list '(%jacobi_ds) u m) form)))))
3645 ;; jacobi_dc(u,m) = jacobi_dn/jacobi_cn
3646 (defmfun $jacobi_dc (u m)
3647 (simplify (list '(%jacobi_dc) (resimplify u) (resimplify m))))
3649 (defprop %jacobi_dc simp-%jacobi_dc operators)
3651 (defprop %jacobi_dc
3652 ((u m)
3653 ;; wrt u
3654 ((mtimes) ((mplus) 1 ((mtimes) -1 m))
3655 ((mexpt) ((%jacobi_cn) u m) -2)
3656 ((%jacobi_sn) u m))
3657 ;; wrt m
3658 ((mplus)
3659 ((mtimes) ((mexpt) ((%jacobi_cn) u m) -1)
3660 ((mplus)
3661 ((mtimes) ((rat) -1 2)
3662 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3663 ((%jacobi_dn) u m)
3664 ((mexpt) ((%jacobi_sn) u m) 2))
3665 ((mtimes) ((rat) -1 2) ((%jacobi_cn) u m)
3666 ((%jacobi_sn) u m)
3667 ((mplus) u
3668 ((mtimes) -1
3669 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3670 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
3671 m))))))
3672 ((mtimes) -1 ((mexpt) ((%jacobi_cn) u m) -2)
3673 ((%jacobi_dn) u m)
3674 ((mplus)
3675 ((mtimes) ((rat) -1 2)
3676 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3677 ((%jacobi_cn) u m)
3678 ((mexpt) ((%jacobi_sn) u m) 2))
3679 ((mtimes) ((rat) -1 2) ((mexpt) m -1)
3680 ((%jacobi_dn) u m) ((%jacobi_sn) u m)
3681 ((mplus) u
3682 ((mtimes) -1
3683 ((mexpt) ((mplus) 1 ((mtimes) -1 m)) -1)
3684 (($elliptic_e) ((%asin) ((%jacobi_sn) u m))
3685 m))))))))
3686 grad)
3688 (defun simp-%jacobi_dc (form unused z)
3689 (declare (ignore unused))
3690 (twoargcheck form)
3691 (let ((u (simpcheck (cadr form) z))
3692 (m (simpcheck (caddr form) z))
3693 coef args)
3694 (cond
3695 ((float-numerical-eval-p u m)
3696 (let ((fu (bigfloat:to ($float u)))
3697 (fm (bigfloat:to ($float m))))
3698 (to (bigfloat:/ (bigfloat::dn fu fm) (bigfloat::cn fu fm)))))
3699 ((setf args (complex-float-numerical-eval-p u m))
3700 (destructuring-bind (u m)
3701 args
3702 (let ((fu (bigfloat:to ($float u)))
3703 (fm (bigfloat:to ($float m))))
3704 (to (bigfloat:/ (bigfloat::dn fu fm) (bigfloat::cn fu fm))))))
3705 ((bigfloat-numerical-eval-p u m)
3706 (let ((uu (bigfloat:to ($bfloat u)))
3707 (mm (bigfloat:to ($bfloat m))))
3708 (to (bigfloat:/ (bigfloat::dn uu mm)
3709 (bigfloat::cn uu mm)))))
3710 ((setf args (complex-bigfloat-numerical-eval-p u m))
3711 (destructuring-bind (u m)
3712 args
3713 (let ((uu (bigfloat:to ($bfloat u)))
3714 (mm (bigfloat:to ($bfloat m))))
3715 (to (bigfloat:/ (bigfloat::dn uu mm)
3716 (bigfloat::cn uu mm))))))
3717 ((zerop1 u)
3719 ((zerop1 m)
3720 ;; A&S 16.6.7
3721 (take '(%sec) u))
3722 ((onep1 m)
3723 ;; A&S 16.6.7
3725 ((and $trigsign (mminusp* u))
3726 (cons-exp '%jacobi_dc (neg u) m))
3727 ((and $triginverses
3728 (listp u)
3729 (member (caar u) '(%inverse_jacobi_sn
3730 %inverse_jacobi_ns
3731 %inverse_jacobi_cn
3732 %inverse_jacobi_nc
3733 %inverse_jacobi_dn
3734 %inverse_jacobi_nd
3735 %inverse_jacobi_sc
3736 %inverse_jacobi_cs
3737 %inverse_jacobi_sd
3738 %inverse_jacobi_ds
3739 %inverse_jacobi_cd
3740 %inverse_jacobi_dc))
3741 (alike1 (third u) m))
3742 (cond ((eq (caar u) '%inverse_jacobi_dc)
3743 (second u))
3745 ;; Express in terms of dn and cn
3746 (div ($jacobi_dn u m)
3747 ($jacobi_cn u m)))))
3748 ;; A&S 16.20 (Jacobi's Imaginary transformation)
3749 ((and $%iargs (multiplep u '$%i))
3750 ;; dc(i*u) = dn(i*u)/cn(i*u) = dc(u,m1)/nc(u,m1) = dn(u,m1)
3751 (cons-exp '%jacobi_dn (coeff u '$%i 1) (add 1 (neg m))))
3752 ((setf coef (kc-arg2 u m))
3753 ;; See A&S 16.8.7
3754 (destructuring-bind (lin const)
3755 coef
3756 (cond ((integerp lin)
3757 (ecase (mod lin 4)
3759 ;; dc(4*m*K + u) = dc(u)
3760 ;; dc(0) = 1
3761 (if (zerop1 const)
3763 `((%jacobi_dc) ,const ,m)))
3765 ;; dc(4*m*K + K + u) = dc(K+u) = -ns(u)
3766 ;; dc(K) = pole
3767 (if (zerop1 const)
3768 (dbz-err1 'jacobi_dc)
3769 (neg `((%jacobi_ns simp) ,const ,m))))
3771 ;; dc(4*m*K + 2*K + u) = dc(2*K+u) = -dc(u)
3772 ;; dc(2K) = -1
3773 (if (zerop1 const)
3775 (neg `((%jacobi_dc) ,const ,m))))
3777 ;; dc(4*m*K + 3*K + u) = dc(2*K + K + u) =
3778 ;; -dc(K+u) = ns(u)
3779 ;; dc(3*K) = ns(0) = inf
3780 (if (zerop1 const)
3781 (dbz-err1 'jacobi_dc)
3782 `((%jacobi_dc simp) ,const ,m)))))
3783 ((and (alike1 lin 1//2)
3784 (zerop1 const))
3785 ;; jacobi_dn/jacobi_cn
3786 `((mtimes)
3787 ((%jacobi_dn) ((mtimes) ((rat) 1 2)
3788 ((%elliptic_kc) ,m))
3790 ((mexpt)
3791 ((%jacobi_cn) ((mtimes) ((rat) 1 2)
3792 ((%elliptic_kc) ,m))
3794 -1)))
3796 ;; Nothing to do
3797 (eqtest (list '(%jacobi_dc) u m) form)))))
3799 ;; Nothing to do
3800 (eqtest (list '(%jacobi_dc) u m) form)))))
3802 ;;; Other inverse Jacobian functions
3804 ;; inverse_jacobi_ns(x)
3806 ;; Let u = inverse_jacobi_ns(x). Then jacobi_ns(u) = x or
3807 ;; 1/jacobi_sn(u) = x or
3809 ;; jacobi_sn(u) = 1/x
3811 ;; so u = inverse_jacobi_sn(1/x)
3813 (defmfun $inverse_jacobi_ns (u m)
3814 (simplify (list '(%inverse_jacobi_ns) (resimplify u) (resimplify m))))
3816 (defprop %inverse_jacobi_ns
3817 ((x m)
3818 ;; Whittaker and Watson, example in 22.122
3819 ;; inverse_jacobi_ns(u,m) = integrate(1/sqrt(t^2-1)/sqrt(t^2-m), t, u, inf)
3820 ;; -> -1/sqrt(x^2-1)/sqrt(x^2-m)
3821 ((mtimes) -1
3822 ((mexpt) ((mplus) -1 ((mexpt) x 2)) ((rat) -1 2))
3823 ((mexpt)
3824 ((mplus) ((mtimes simp ratsimp) -1 m) ((mexpt) x 2))
3825 ((rat) -1 2)))
3826 ;; wrt m
3827 ; ((%derivative) ((%inverse_jacobi_ns) x m) m 1)
3828 nil)
3829 grad)
3831 (defprop %inverse_jacobi_ns simp-%inverse_jacobi_ns operators)
3833 (defun simp-%inverse_jacobi_ns (form unused z)
3834 (declare (ignore unused))
3835 (twoargcheck form)
3836 (let ((u (simpcheck (cadr form) z))
3837 (m (simpcheck (caddr form) z))
3838 args)
3839 (cond
3840 ((float-numerical-eval-p u m)
3841 ;; Numerically evaluate asn
3843 ;; ans(x,m) = asn(1/x,m) = F(asin(1/x),m)
3844 (to (elliptic-f (cl:asin (/ ($float u))) ($float m))))
3845 ((complex-float-numerical-eval-p u m)
3846 (to (elliptic-f (cl:asin (/ (complex ($realpart ($float u)) ($imagpart ($float u)))))
3847 (complex ($realpart ($float m)) ($imagpart ($float m))))))
3848 ((bigfloat-numerical-eval-p u m)
3849 (to (bigfloat::bf-elliptic-f (bigfloat:asin (bigfloat:/ (bigfloat:to ($bfloat u))))
3850 (bigfloat:to ($bfloat m)))))
3851 ((setf args (complex-bigfloat-numerical-eval-p u m))
3852 (destructuring-bind (u m)
3853 args
3854 (to (bigfloat::bf-elliptic-f (bigfloat:asin (bigfloat:/ (bigfloat:to ($bfloat u))))
3855 (bigfloat:to ($bfloat m))))))
3856 ((zerop1 m)
3857 ;; ans(x,0) = F(asin(1/x),0) = asin(1/x)
3858 `(($elliptic_f) ((%asin) ((mexpt) ,u -1)) 0))
3859 ((onep1 m)
3860 ;; ans(x,1) = F(asin(1/x),1) = log(tan(pi/2+asin(1/x)/2))
3861 `(($elliptic_f) ((%asin) ((mexpt) ,u -1)) 1))
3862 ((onep1 u)
3863 `((%elliptic_kc) ,m))
3864 ((alike1 u -1)
3865 (neg `((%elliptic_kc) ,m)))
3866 ((and (eq $triginverses '$all)
3867 (listp u)
3868 (eq (caar u) '%jacobi_ns)
3869 (alike1 (third u) m))
3870 ;; inverse_jacobi_ns(ns(u)) = u
3871 (second u))
3873 ;; Nothing to do
3874 (eqtest (list '(%inverse_jacobi_ns) u m) form)))))
3876 ;; inverse_jacobi_nc(x)
3878 ;; Let u = inverse_jacobi_nc(x). Then jacobi_nc(u) = x or
3879 ;; 1/jacobi_cn(u) = x or
3881 ;; jacobi_cn(u) = 1/x
3883 ;; so u = inverse_jacobi_cn(1/x)
3885 (defmfun $inverse_jacobi_nc (u m)
3886 (simplify (list '(%inverse_jacobi_nc) (resimplify u) (resimplify m))))
3888 (defprop %inverse_jacobi_nc
3889 ((x m)
3890 ;; Whittaker and Watson, example in 22.122
3891 ;; inverse_jacobi_nc(u,m) = integrate(1/sqrt(t^2-1)/sqrt((1-m)*t^2+m), t, 1, u)
3892 ;; -> 1/sqrt(x^2-1)/sqrt((1-m)*x^2+m)
3893 ((mtimes)
3894 ((mexpt) ((mplus) -1 ((mexpt) x 2)) ((rat) -1 2))
3895 ((mexpt)
3896 ((mplus) m
3897 ((mtimes) -1 ((mplus) -1 m) ((mexpt) x 2)))
3898 ((rat) -1 2)))
3899 ;; wrt m
3900 ; ((%derivative) ((%inverse_jacobi_nc) x m) m 1)
3901 nil)
3902 grad)
3904 (defprop %inverse_jacobi_nc simp-%inverse_jacobi_nc operators)
3906 (defun simp-%inverse_jacobi_nc (form unused z)
3907 (declare (ignore unused))
3908 (twoargcheck form)
3909 (let ((u (simpcheck (cadr form) z))
3910 (m (simpcheck (caddr form) z)))
3911 (cond ((or (float-numerical-eval-p u m)
3912 (complex-float-numerical-eval-p u m)
3913 (bigfloat-numerical-eval-p u m)
3914 (complex-bigfloat-numerical-eval-p u m))
3916 ($inverse_jacobi_cn ($rectform (div 1 u)) m))
3917 ((onep1 u)
3919 ((alike1 u -1)
3920 `((mtimes) 2 ((%elliptic_kc) ,m)))
3921 ((and (eq $triginverses '$all)
3922 (listp u)
3923 (eq (caar u) '%jacobi_nc)
3924 (alike1 (third u) m))
3925 ;; inverse_jacobi_nc(nc(u)) = u
3926 (second u))
3928 ;; Nothing to do
3929 (eqtest (list '(%inverse_jacobi_nc) u m) form)))))
3931 ;; inverse_jacobi_nd(x)
3933 ;; Let u = inverse_jacobi_nd(x). Then jacobi_nd(u) = x or
3934 ;; 1/jacobi_dn(u) = x or
3936 ;; jacobi_dn(u) = 1/x
3938 ;; so u = inverse_jacobi_dn(1/x)
3940 (defmfun $inverse_jacobi_nd (u m)
3941 (simplify (list '(%inverse_jacobi_nd) (resimplify u) (resimplify m))))
3943 (defprop %inverse_jacobi_nd
3944 ((x m)
3945 ;; Whittaker and Watson, example in 22.122
3946 ;; inverse_jacobi_nd(u,m) = integrate(1/sqrt(t^2-1)/sqrt(1-(1-m)*t^2), t, 1, u)
3947 ;; -> 1/sqrt(u^2-1)/sqrt(1-(1-m)*t^2)
3948 ((mtimes)
3949 ((mexpt) ((mplus) -1 ((mexpt simp ratsimp) x 2))
3950 ((rat) -1 2))
3951 ((mexpt)
3952 ((mplus) 1
3953 ((mtimes) ((mplus) -1 m) ((mexpt simp ratsimp) x 2)))
3954 ((rat) -1 2)))
3955 ;; wrt m
3956 ; ((%derivative) ((%inverse_jacobi_nd) x m) m 1)
3957 nil)
3958 grad)
3960 (defprop %inverse_jacobi_nd simp-%inverse_jacobi_nd operators)
3962 (defun simp-%inverse_jacobi_nd (form unused z)
3963 (declare (ignore unused))
3964 (twoargcheck form)
3965 (let ((u (simpcheck (cadr form) z))
3966 (m (simpcheck (caddr form) z)))
3967 (cond ((or (float-numerical-eval-p u m)
3968 (complex-float-numerical-eval-p u m)
3969 (bigfloat-numerical-eval-p u m)
3970 (complex-bigfloat-numerical-eval-p u m))
3971 ($inverse_jacobi_dn ($rectform (div 1 u)) m))
3972 ((onep1 u)
3974 ((onep1 ($ratsimp (mul (power (sub 1 m) 1//2) u)))
3975 ;; jacobi_nd(1/sqrt(1-m),m) = K(m). This follows from
3976 ;; jacobi_dn(sqrt(1-m),m) = K(m).
3977 ($elliptic_kc m))
3978 ((and (eq $triginverses '$all)
3979 (listp u)
3980 (eq (caar u) '%jacobi_nd)
3981 (alike1 (third u) m))
3982 ;; inverse_jacobi_nd(nd(u)) = u
3983 (second u))
3985 ;; Nothing to do
3986 (eqtest (list '(%inverse_jacobi_nd) u m) form)))))
3988 ;; inverse_jacobi_sc(x)
3990 ;; Let u = inverse_jacobi_sc(x). Then jacobi_sc(u) = x or
3991 ;; x = jacobi_sn(u)/jacobi_cn(u)
3993 ;; x^2 = sn^2/cn^2
3994 ;; = sn^2/(1-sn^2)
3996 ;; so
3998 ;; sn^2 = x^2/(1+x^2)
4000 ;; sn(u) = x/sqrt(1+x^2)
4002 ;; u = inverse_sn(x/sqrt(1+x^2))
4005 (defmfun $inverse_jacobi_sc (u m)
4006 (simplify (list '(%inverse_jacobi_sc) (resimplify u) (resimplify m))))
4008 (defprop %inverse_jacobi_sc
4009 ((x m)
4010 ;; Whittaker and Watson, example in 22.122
4011 ;; inverse_jacobi_sc(u,m) = integrate(1/sqrt(1+t^2)/sqrt(1+(1-m)*t^2), t, 0, u)
4012 ;; -> 1/sqrt(1+x^2)/sqrt(1+(1-m)*x^2)
4013 ((mtimes)
4014 ((mexpt) ((mplus) 1 ((mexpt) x 2))
4015 ((rat) -1 2))
4016 ((mexpt)
4017 ((mplus) 1
4018 ((mtimes) -1 ((mplus) -1 m) ((mexpt) x 2)))
4019 ((rat) -1 2)))
4020 ;; wrt m
4021 ; ((%derivative) ((%inverse_jacobi_sc) x m) m 1)
4022 nil)
4023 grad)
4025 (defprop %inverse_jacobi_sc simp-%inverse_jacobi_sc operators)
4027 (defun simp-%inverse_jacobi_sc (form unused z)
4028 (declare (ignore unused))
4029 (twoargcheck form)
4030 (let ((u (simpcheck (cadr form) z))
4031 (m (simpcheck (caddr form) z)))
4032 (cond ((or (float-numerical-eval-p u m)
4033 (complex-float-numerical-eval-p u m)
4034 (bigfloat-numerical-eval-p u m)
4035 (complex-bigfloat-numerical-eval-p u m))
4036 ($inverse_jacobi_sn
4037 ($rectform (div u (power (add 1 (mul u u)) 1//2)))
4039 ((zerop1 u)
4040 ;; jacobi_sc(0,m) = 0
4042 ((and (eq $triginverses '$all)
4043 (listp u)
4044 (eq (caar u) '%jacobi_sc)
4045 (alike1 (third u) m))
4046 ;; inverse_jacobi_sc(sc(u)) = u
4047 (second u))
4049 ;; Nothing to do
4050 (eqtest (list '(%inverse_jacobi_sc) u m) form)))))
4052 ;; inverse_jacobi_sd(x)
4054 ;; Let u = inverse_jacobi_sd(x). Then jacobi_sd(u) = x or
4055 ;; x = jacobi_sn(u)/jacobi_dn(u)
4057 ;; x^2 = sn^2/dn^2
4058 ;; = sn^2/(1-m*sn^2)
4060 ;; so
4062 ;; sn^2 = x^2/(1+m*x^2)
4064 ;; sn(u) = x/sqrt(1+m*x^2)
4066 ;; u = inverse_sn(x/sqrt(1+m*x^2))
4069 (defmfun $inverse_jacobi_sd (u m)
4070 (simplify (list '(%inverse_jacobi_sd) (resimplify u) (resimplify m))))
4072 (defprop %inverse_jacobi_sd
4073 ((x m)
4074 ;; Whittaker and Watson, example in 22.122
4075 ;; inverse_jacobi_sd(u,m) = integrate(1/sqrt(1-(1-m)*t^2)/sqrt(1+m*t^2), t, 0, u)
4076 ;; -> 1/sqrt(1-(1-m)*x^2)/sqrt(1+m*x^2)
4077 ((mtimes)
4078 ((mexpt)
4079 ((mplus) 1 ((mtimes) ((mplus) -1 m) ((mexpt) x 2)))
4080 ((rat) -1 2))
4081 ((mexpt) ((mplus) 1 ((mtimes) m ((mexpt) x 2)))
4082 ((rat) -1 2)))
4083 ;; wrt m
4084 ; ((%derivative) ((%inverse_jacobi_sd) x m) m 1)
4085 nil)
4086 grad)
4088 (defprop %inverse_jacobi_sd simp-%inverse_jacobi_sd operators)
4090 (defun simp-%inverse_jacobi_sd (form unused z)
4091 (declare (ignore unused))
4092 (twoargcheck form)
4093 (let ((u (simpcheck (cadr form) z))
4094 (m (simpcheck (caddr form) z)))
4095 (cond ((or (float-numerical-eval-p u m)
4096 (complex-float-numerical-eval-p u m)
4097 (bigfloat-numerical-eval-p u m)
4098 (complex-bigfloat-numerical-eval-p u m))
4099 ($inverse_jacobi_sn
4100 ($rectform (div u (power (add 1 (mul m (mul u u))) 1//2)))
4102 ((zerop1 u)
4104 ((eql 0 ($ratsimp (sub u (div 1 (power (sub 1 m) 1//2)))))
4105 ;; inverse_jacobi_sd(1/sqrt(1-m), m) = elliptic_kc(m)
4107 ;; We can see this from inverse_jacobi_sd(x,m) =
4108 ;; inverse_jacobi_sn(x/sqrt(1+m*x^2), m). So
4109 ;; inverse_jacobi_sd(1/sqrt(1-m),m) = inverse_jacobi_sn(1,m)
4110 ($elliptic_kc m))
4111 ((and (eq $triginverses '$all)
4112 (listp u)
4113 (eq (caar u) '%jacobi_sd)
4114 (alike1 (third u) m))
4115 ;; inverse_jacobi_sd(sd(u)) = u
4116 (second u))
4118 ;; Nothing to do
4119 (eqtest (list '(%inverse_jacobi_sd) u m) form)))))
4121 ;; inverse_jacobi_cs(x)
4123 ;; Let u = inverse_jacobi_cs(x). Then jacobi_cs(u) = x or
4124 ;; 1/x = 1/jacobi_cs(u) = jacobi_sc(u)
4126 ;; u = inverse_sc(1/x)
4129 (defmfun $inverse_jacobi_cs (u m)
4130 (simplify (list '(%inverse_jacobi_cs) (resimplify u) (resimplify m))))
4132 (defprop %inverse_jacobi_cs
4133 ((x m)
4134 ;; Whittaker and Watson, example in 22.122
4135 ;; inverse_jacobi_cs(u,m) = integrate(1/sqrt(t^2+1)/sqrt(t^2+(1-m)), t, u, inf)
4136 ;; -> -1/sqrt(x^2+1)/sqrt(x^2+(1-m))
4137 ((mtimes) -1
4138 ((mexpt) ((mplus) 1 ((mexpt simp ratsimp) x 2))
4139 ((rat) -1 2))
4140 ((mexpt) ((mplus) 1
4141 ((mtimes simp ratsimp) -1 m)
4142 ((mexpt simp ratsimp) x 2))
4143 ((rat) -1 2)))
4144 ;; wrt m
4145 ; ((%derivative) ((%inverse_jacobi_cs) x m) m 1)
4146 nil)
4147 grad)
4149 (defprop %inverse_jacobi_cs simp-%inverse_jacobi_cs operators)
4151 (defun simp-%inverse_jacobi_cs (form unused z)
4152 (declare (ignore unused))
4153 (twoargcheck form)
4154 (let ((u (simpcheck (cadr form) z))
4155 (m (simpcheck (caddr form) z)))
4156 (cond ((or (float-numerical-eval-p u m)
4157 (complex-float-numerical-eval-p u m)
4158 (bigfloat-numerical-eval-p u m)
4159 (complex-bigfloat-numerical-eval-p u m))
4160 ($inverse_jacobi_sc ($rectform (div 1 u)) m))
4161 ((zerop1 u)
4162 `((%elliptic_kc) ,m))
4164 ;; Nothing to do
4165 (eqtest (list '(%inverse_jacobi_cs) u m) form)))))
4167 ;; inverse_jacobi_cd(x)
4169 ;; Let u = inverse_jacobi_cd(x). Then jacobi_cd(u) = x or
4170 ;; x = jacobi_cn(u)/jacobi_dn(u)
4172 ;; x^2 = cn^2/dn^2
4173 ;; = (1-sn^2)/(1-m*sn^2)
4175 ;; or
4177 ;; sn^2 = (1-x^2)/(1-m*x^2)
4179 ;; sn(u) = sqrt(1-x^2)/sqrt(1-m*x^2)
4181 ;; u = inverse_sn(sqrt(1-x^2)/sqrt(1-m*x^2))
4184 (defmfun $inverse_jacobi_cd (u m)
4185 (simplify (list '(%inverse_jacobi_cd) (resimplify u) (resimplify m))))
4187 (defprop %inverse_jacobi_cd
4188 ((x m)
4189 ;; Whittaker and Watson, example in 22.122
4190 ;; inverse_jacobi_cd(u,m) = integrate(1/sqrt(1-t^2)/sqrt(1-m*t^2), t, u, 1)
4191 ;; -> -1/sqrt(1-x^2)/sqrt(1-m*x^2)
4192 ((mtimes) -1
4193 ((mexpt)
4194 ((mplus) 1 ((mtimes) -1 ((mexpt) x 2)))
4195 ((rat) -1 2))
4196 ((mexpt)
4197 ((mplus) 1 ((mtimes) -1 m ((mexpt) x 2)))
4198 ((rat) -1 2)))
4199 ;; wrt m
4200 ; ((%derivative) ((%inverse_jacobi_cd) x m) m 1)
4201 nil)
4202 grad)
4204 (defprop %inverse_jacobi_cd simp-%inverse_jacobi_cd operators)
4206 (defun simp-%inverse_jacobi_cd (form unused z)
4207 (declare (ignore unused))
4208 (twoargcheck form)
4209 (let ((u (simpcheck (cadr form) z))
4210 (m (simpcheck (caddr form) z)))
4211 (cond ((or (complex-float-numerical-eval-p u m)
4212 (complex-bigfloat-numerical-eval-p u m))
4213 (let (($numer t))
4214 ($inverse_jacobi_sn
4215 ($rectform (div (power (mul (sub 1 u) (add 1 u)) 1//2)
4216 (power (sub 1 (mul m (mul u u))) 1//2)))
4217 m)))
4218 ((onep1 u)
4220 ((zerop1 u)
4221 `((%elliptic_kc) ,m))
4222 ((and (eq $triginverses '$all)
4223 (listp u)
4224 (eq (caar u) '%jacobi_cd)
4225 (alike1 (third u) m))
4226 ;; inverse_jacobi_cd(cd(u)) = u
4227 (second u))
4229 ;; Nothing to do
4230 (eqtest (list '(%inverse_jacobi_cd) u m) form)))))
4232 ;; inverse_jacobi_ds(x)
4234 ;; Let u = inverse_jacobi_ds(x). Then jacobi_ds(u) = x or
4235 ;; 1/x = 1/jacobi_ds(u) = jacobi_sd(u)
4237 ;; u = inverse_sd(1/x)
4240 (defmfun $inverse_jacobi_ds (u m)
4241 (simplify (list '(%inverse_jacobi_ds) (resimplify u) (resimplify m))))
4243 (defprop %inverse_jacobi_ds
4244 ((x m)
4245 ;; Whittaker and Watson, example in 22.122
4246 ;; inverse_jacobi_ds(u,m) = integrate(1/sqrt(t^2-(1-m))/sqrt(t^2+m), t, u, inf)
4247 ;; -> -1/sqrt(x^2-(1-m))/sqrt(x^2+m)
4248 ((mtimes) -1
4249 ((mexpt)
4250 ((mplus) -1 m ((mexpt simp ratsimp) x 2))
4251 ((rat) -1 2))
4252 ((mexpt)
4253 ((mplus) m ((mexpt simp ratsimp) x 2))
4254 ((rat) -1 2)))
4255 ;; wrt m
4256 ; ((%derivative) ((%inverse_jacobi_ds) x m) m 1)
4257 nil)
4258 grad)
4260 (defprop %inverse_jacobi_ds simp-%inverse_jacobi_ds operators)
4262 (defun simp-%inverse_jacobi_ds (form unused z)
4263 (declare (ignore unused))
4264 (twoargcheck form)
4265 (let ((u (simpcheck (cadr form) z))
4266 (m (simpcheck (caddr form) z)))
4267 (cond ((or (float-numerical-eval-p u m)
4268 (complex-float-numerical-eval-p u m)
4269 (bigfloat-numerical-eval-p u m)
4270 (complex-bigfloat-numerical-eval-p u m))
4271 ($inverse_jacobi_sd ($rectform (div 1 u)) m))
4272 ((and $trigsign (mminusp* u))
4273 (neg (cons-exp '%inverse_jacobi_ds (neg u) m)))
4274 ((eql 0 ($ratsimp (sub u (power (sub 1 m) 1//2))))
4275 ;; inverse_jacobi_ds(sqrt(1-m),m) = elliptic_kc(m)
4277 ;; Since inverse_jacobi_ds(sqrt(1-m), m) =
4278 ;; inverse_jacobi_sd(1/sqrt(1-m),m). And we know from
4279 ;; above that this is elliptic_kc(m)
4280 ($elliptic_kc m))
4281 ((and (eq $triginverses '$all)
4282 (listp u)
4283 (eq (caar u) '%jacobi_ds)
4284 (alike1 (third u) m))
4285 ;; inverse_jacobi_ds(ds(u)) = u
4286 (second u))
4288 ;; Nothing to do
4289 (eqtest (list '(%inverse_jacobi_ds) u m) form)))))
4292 ;; inverse_jacobi_dc(x)
4294 ;; Let u = inverse_jacobi_dc(x). Then jacobi_dc(u) = x or
4295 ;; 1/x = 1/jacobi_dc(u) = jacobi_cd(u)
4297 ;; u = inverse_cd(1/x)
4300 (defmfun $inverse_jacobi_dc (u m)
4301 (simplify (list '(%inverse_jacobi_dc) (resimplify u) (resimplify m))))
4303 (defprop %inverse_jacobi_dc
4304 ((x m)
4305 ;; Note: Whittaker and Watson, example in 22.122 says
4306 ;; inverse_jacobi_dc(u,m) = integrate(1/sqrt(t^2-1)/sqrt(t^2-m),
4307 ;; t, u, 1) but that seems wrong. A&S 17.4.47 says
4308 ;; integrate(1/sqrt(t^2-1)/sqrt(t^2-m), t, a, u) =
4309 ;; inverse_jacobi_cd(x,m). Lawden 3.2.8 says the same.
4310 ;; functions.wolfram.com says the derivative is
4311 ;; 1/sqrt(t^2-1)/sqrt(t^2-m).
4312 ((mtimes)
4313 ((mexpt)
4314 ((mplus) -1 ((mexpt simp ratsimp) x 2))
4315 ((rat) -1 2))
4316 ((mexpt)
4317 ((mplus)
4318 ((mtimes simp ratsimp) -1 m)
4319 ((mexpt simp ratsimp) x 2))
4320 ((rat) -1 2)))
4321 ;; wrt m
4322 ; ((%derivative) ((%inverse_jacobi_dc) x m) m 1)
4323 nil)
4324 grad)
4326 (defprop %inverse_jacobi_dc simp-%inverse_jacobi_dc operators)
4328 (defun simp-%inverse_jacobi_dc (form unused z)
4329 (declare (ignore unused))
4330 (twoargcheck form)
4331 (let ((u (simpcheck (cadr form) z))
4332 (m (simpcheck (caddr form) z)))
4333 (cond ((or (complex-float-numerical-eval-p u m)
4334 (complex-bigfloat-numerical-eval-p u m))
4335 ($inverse_jacobi_cd ($rectform (div 1 u)) m))
4336 ((onep1 u)
4338 ((and (eq $triginverses '$all)
4339 (listp u)
4340 (eq (caar u) '%jacobi_dc)
4341 (alike1 (third u) m))
4342 ;; inverse_jacobi_dc(dc(u)) = u
4343 (second u))
4345 ;; Nothing to do
4346 (eqtest (list '(%inverse_jacobi_dc) u m) form)))))
4348 ;; Convert an inverse Jacobian function into the equivalent elliptic
4349 ;; integral F.
4351 ;; See A&S 17.4.41-17.4.52.
4352 (defun make-elliptic-f (e)
4353 (cond ((atom e)
4355 ((member (caar e) '(%inverse_jacobi_sc %inverse_jacobi_cs
4356 %inverse_jacobi_nd %inverse_jacobi_dn
4357 %inverse_jacobi_sn %inverse_jacobi_cd
4358 %inverse_jacobi_dc %inverse_jacobi_ns
4359 %inverse_jacobi_nc %inverse_jacobi_ds
4360 %inverse_jacobi_sd %inverse_jacobi_cn))
4361 ;; We have some inverse Jacobi function. Convert it to the F form.
4362 (destructuring-bind ((fn &rest ops) u m)
4364 (declare (ignore ops))
4365 (ecase fn
4366 (%inverse_jacobi_sc
4367 ;; A&S 17.4.41
4368 `(($elliptic_f) ((%atan) ,u) ,m))
4369 (%inverse_jacobi_cs
4370 ;; A&S 17.4.42
4371 `(($elliptic_f) ((%atan) ((mexpt) ,u -1)) ,m))
4372 (%inverse_jacobi_nd
4373 ;; A&S 17.4.43
4374 `(($elliptic_f)
4375 ((%asin) ((mtimes)
4376 ((mexpt) ,m ((rat) -1 2))
4377 ((mexpt) ,u -1)
4378 ((mexpt) ((mplus) -1 ((mexpt) ,u 2))
4379 ((rat) 1 2))))
4380 ,m))
4381 (%inverse_jacobi_dn
4382 ;; A&S 17.4.44
4383 `(($elliptic_f)
4384 ((%asin)
4385 ((mtimes) ((mexpt) ,m ((rat) -1 2))
4386 ((mexpt) ((mplus) 1 ((mtimes) -1 ((mexpt) ,u 2)))
4387 ((rat) 1 2))))
4388 ,m))
4389 (%inverse_jacobi_sn
4390 ;; A&S 17.4.45
4391 `(($elliptic_f) ((%asin) ,u) ,m))
4392 (%inverse_jacobi_cd
4393 ;; A&S 17.4.46
4394 `(($elliptic_f)
4395 ((%asin)
4396 ((mexpt) ((mtimes) ((mplus) 1
4397 ((mtimes) -1 ((mexpt) ,u 2)))
4398 ((mexpt) ((mplus) 1
4399 ((mtimes) -1 ,m ((mexpt) ,u 2)))
4400 -1))
4401 ((rat) 1 2)))
4402 ,m))
4403 (%inverse_jacobi_dc
4404 ;; A&S 17.4.47
4405 `(($elliptic_f)
4406 ((%asin)
4407 ((mexpt)
4408 ((mtimes) ((mplus) -1 ((mexpt) ,u 2))
4409 ((mexpt) ((mplus) ((mtimes) -1 ,m) ((mexpt) ,u 2)) -1))
4410 ((rat) 1 2)))
4411 ,m))
4412 (%inverse_jacobi_ns
4413 ;; A&S 17.4.48
4414 `(($elliptic_f) ((%asin) ((mexpt) ,u -1)) ,m))
4415 (%inverse_jacobi_nc
4416 ;; A&S 17.4.49
4417 `(($elliptic_f) ((%acos) ((mexpt) ,u -1)) ,m))
4418 (%inverse_jacobi_ds
4419 ;; A&S 17.4.50
4420 `(($elliptic_f)
4421 ((%asin) ((mexpt) ((mplus) ,m ((mexpt) ,u 2))
4422 ((rat) -1 2)))
4423 ,m))
4424 (%inverse_jacobi_sd
4425 ;; A&S 17.4.51
4426 `(($elliptic_f)
4427 ((%asin)
4428 ((mtimes) ,u
4429 ((mexpt) ((mplus) 1 ((mtimes) ,m ((mexpt) ,u 2)))
4430 ((rat) -1 2))))
4431 ,m))
4432 (%inverse_jacobi_cn
4433 ;; A&S 17.4.52
4434 `(($elliptic_f) ((%acos) ,u) ,m)))))
4436 (recur-apply #'make-elliptic-f e))))
4438 (defmfun $make_elliptic_f (e)
4439 (if (atom e)
4441 (simplify (make-elliptic-f e))))
4443 (defun make-elliptic-e (e)
4444 (cond ((atom e) e)
4445 ((eq (caar e) '$elliptic_eu)
4446 (destructuring-bind ((ffun &rest ops) u m) e
4447 (declare (ignore ffun ops))
4448 `(($elliptic_e) ((%asin) ((%jacobi_sn) ,u ,m)) ,m)))
4450 (recur-apply #'make-elliptic-e e))))
4452 (defmfun $make_elliptic_e (e)
4453 (if (atom e)
4455 (simplify (make-elliptic-e e))))
4458 ;; Eu(u,m) = integrate(jacobi_dn(v,m)^2,v,0,u)
4459 ;; = integrate(sqrt((1-m*t^2)/(1-t^2)),t,0,jacobi_sn(u,m))
4461 ;; Eu(u,m) = E(am(u),m)
4463 ;; where E(u,m) is elliptic-e above.
4465 ;; Checks.
4466 ;; Lawden gives the following relationships
4468 ;; E(u+v) = E(u) + E(v) - m*sn(u)*sn(v)*sn(u+v)
4469 ;; E(u,0) = u, E(u,1) = tanh u
4471 ;; E(i*u,k) = i*sc(u,k')*dn(u,k') - i*E(u,k') + i*u
4473 ;; E(2*i*K') = 2*i*(K'-E')
4475 ;; E(u + 2*i*K') = E(u) + 2*i*(K' - E')
4477 ;; E(u+K) = E(u) + E - k^2*sn(u)*cd(u)
4478 (defun elliptic-eu (u m)
4479 (cond ((realp u)
4480 ;; E(u + 2*n*K) = E(u) + 2*n*E
4481 (let ((ell-k (to (elliptic-k m)))
4482 (ell-e (elliptic-ec m)))
4483 (multiple-value-bind (n u-rem)
4484 (floor u (* 2 ell-k))
4485 ;; 0 <= u-rem < 2*K
4486 (+ (* 2 n ell-e)
4487 (cond ((>= u-rem ell-k)
4488 ;; 0 <= u-rem < K so
4489 ;; E(u + K) = E(u) + E - m*sn(u)*cd(u)
4490 (let ((u-k (- u ell-k)))
4491 (- (+ (elliptic-e (cl:asin (bigfloat::sn u-k m)) m)
4492 ell-e)
4493 (/ (* m (bigfloat::sn u-k m) (bigfloat::cn u-k m))
4494 (bigfloat::dn u-k m)))))
4496 (elliptic-e (cl:asin (bigfloat::sn u m)) m)))))))
4497 ((complexp u)
4498 ;; From Lawden:
4500 ;; E(u+i*v, m) = E(u,m) -i*E(v,m') + i*v + i*sc(v,m')*dn(v,m')
4501 ;; -i*m*sn(u,m)*sc(v,m')*sn(u+i*v,m)
4503 (let ((u-r (realpart u))
4504 (u-i (imagpart u))
4505 (m1 (- 1 m)))
4506 (+ (elliptic-eu u-r m)
4507 (* #c(0 1)
4508 (- (+ u-i
4509 (/ (* (bigfloat::sn u-i m1) (bigfloat::dn u-i m1))
4510 (bigfloat::cn u-i m1)))
4511 (+ (elliptic-eu u-i m1)
4512 (/ (* m (bigfloat::sn u-r m) (bigfloat::sn u-i m1) (bigfloat::sn u m))
4513 (bigfloat::cn u-i m1))))))))))
4515 (defprop $elliptic_eu simp-$elliptic_eu operators)
4516 (defprop $elliptic_eu
4517 ((u m)
4518 ((mexpt) ((%jacobi_dn) u m) 2)
4519 ;; wrt m
4521 grad)
4523 (defun simp-$elliptic_eu (form unused z)
4524 (declare (ignore unused))
4525 (twoargcheck form)
4526 (let ((u (simpcheck (cadr form) z))
4527 (m (simpcheck (caddr form) z)))
4528 (cond
4529 ;; as it stands, ELLIPTIC-EU can't handle bigfloats or complex bigfloats,
4530 ;; so handle only floats and complex floats here.
4531 ((float-numerical-eval-p u m)
4532 (elliptic-eu ($float u) ($float m)))
4533 ((complex-float-numerical-eval-p u m)
4534 (let ((u-r ($realpart u))
4535 (u-i ($imagpart u))
4536 (m ($float m)))
4537 (complexify (elliptic-eu (complex u-r u-i) m))))
4539 (eqtest `(($elliptic_eu) ,u ,m) form)))))
4541 (defmfun $elliptic_eu (u m)
4542 (simplify `(($elliptic_eu) ,(resimplify u) ,(resimplify m))))
4544 (defprop %jacobi_am simp-%jacobi_am operators)
4546 (defmfun $jacobi_am (u m)
4547 (simplify `((%jacobi_am) ,(resimplify u) ,(resimplify m))))
4549 (defun simp-%jacobi_am (form unused z)
4550 (declare (ignore unused))
4551 (twoargcheck form)
4552 (let ((u (simpcheck (cadr form) z))
4553 (m (simpcheck (caddr form) z)))
4554 (cond
4555 ;; as it stands, BIGFLOAT::SN can't handle bigfloats or complex bigfloats,
4556 ;; so handle only floats and complex floats here.
4557 ((float-numerical-eval-p u m)
4558 (cl:asin (bigfloat::sn ($float u) ($float m))))
4559 ((complex-float-numerical-eval-p u m)
4560 (let ((u-r ($realpart ($float u)))
4561 (u-i ($imagpart ($float u)))
4562 (m ($float m)))
4563 (complexify (cl:asin (bigfloat::sn (complex u-r u-i) m)))))
4565 ;; Nothing to do
4566 (eqtest (list '(%jacobi_am) u m) form)))))
4568 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4569 ;; Integrals. At present with respect to first argument only.
4570 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4572 ;; A&S 16.24.1: integrate(jacobi_sn(u,m),u)
4573 ;; = log(jacobi_dn(u,m)-sqrt(m)*jacobi_cn(u,m))/sqrt(m)
4574 (defprop %jacobi_sn
4575 ((u m)
4576 ((mtimes simp) ((mexpt simp) m ((rat simp) -1 2))
4577 ((%log simp)
4578 ((mplus simp)
4579 ((mtimes simp) -1 ((mexpt simp) m ((rat simp) 1 2))
4580 ((%jacobi_cn simp) u m))
4581 ((%jacobi_dn simp) u m))))
4582 nil)
4583 integral)
4585 ;; A&S 16.24.2: integrate(jacobi_cn(u,m),u) = acos(jacobi_dn(u,m))/sqrt(m)
4586 (defprop %jacobi_cn
4587 ((u m)
4588 ((mtimes simp) ((mexpt simp) m ((rat simp) -1 2))
4589 ((%acos simp) ((%jacobi_dn simp) u m)))
4590 nil)
4591 integral)
4593 ;; A&S 16.24.3: integrate(jacobi_dn(u,m),u) = asin(jacobi_sn(u,m))
4594 (defprop %jacobi_dn
4595 ((u m)
4596 ((%asin simp) ((%jacobi_sn simp) u m))
4597 nil)
4598 integral)
4600 ;; A&S 16.24.4: integrate(jacobi_cd(u,m),u)
4601 ;; = log(jacobi_nd(u,m)+sqrt(m)*jacobi_sd(u,m))/sqrt(m)
4602 (defprop %jacobi_cd
4603 ((u m)
4604 ((mtimes simp) ((mexpt simp) m ((rat simp) -1 2))
4605 ((%log simp)
4606 ((mplus simp) ((%jacobi_nd simp) u m)
4607 ((mtimes simp) ((mexpt simp) m ((rat simp) 1 2))
4608 ((%jacobi_sd simp) u m)))))
4609 nil)
4610 integral)
4612 ;; integrate(jacobi_sd(u,m),u)
4614 ;; A&S 16.24.5 gives
4615 ;; asin(-sqrt(m)*jacobi_cd(u,m))/sqrt(m*m_1), where m + m_1 = 1
4616 ;; but this does not pass some simple tests.
4618 ;; functions.wolfram.com 09.35.21.001.01 gives
4619 ;; -asin(sqrt(m)*jacobi_cd(u,m))*sqrt(1-m*jacobi_cd(u,m)^2)*jacobi_dn(u,m)/((1-m)*sqrt(m))
4620 ;; and this does pass.
4621 (defprop %jacobi_sd
4622 ((u m)
4623 ((mtimes simp) -1
4624 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
4625 ((mexpt simp) m ((rat simp) -1 2))
4626 ((mexpt simp)
4627 ((mplus simp) 1
4628 ((mtimes simp) -1 $m ((mexpt simp) ((%jacobi_cd simp) u m) 2)))
4629 ((rat simp) 1 2))
4630 ((%jacobi_dn simp) u m)
4631 ((%asin simp)
4632 ((mtimes simp) ((mexpt simp) m ((rat simp) 1 2))
4633 ((%jacobi_cd simp) u m))))
4634 nil)
4635 integral)
4637 ;; integrate(jacobi_nd(u,m),u)
4639 ;; A&S 16.24.6 gives
4640 ;; acos(jacobi_cd(u,m))/sqrt(m_1), where m + m_1 = 1
4641 ;; but this does not pass some simple tests.
4643 ;; functions.wolfram.com 09.32.21.0001.01 gives
4644 ;; sqrt(1-jacobi_cd(u,m)^2)*acos(jacobi_cd(u,m))/((1-m)*jacobi_sd(u,m))
4645 ;; and this does pass.
4646 (defprop %jacobi_nd
4647 ((u m)
4648 ((mtimes simp) ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m)) -1)
4649 ((mexpt simp)
4650 ((mplus simp) 1
4651 ((mtimes simp) -1 ((mexpt simp) ((%jacobi_cd simp) u m) 2)))
4652 ((rat simp) 1 2))
4653 ((mexpt simp) ((%jacobi_sd simp) u m) -1)
4654 ((%acos simp) ((%jacobi_cd simp) u m)))
4655 nil)
4656 integral)
4658 ;; A&S 16.24.7: integrate(jacobi_dc(u,m),u) = log(jacobi_nc(u,m)+jacobi_sc(u,m))
4659 (defprop %jacobi_dc
4660 ((u m)
4661 ((%log simp) ((mplus simp) ((%jacobi_nc simp) u m) ((%jacobi_sc simp) u m)))
4662 nil)
4663 integral)
4665 ;; A&S 16.24.8: integrate(jacobi_nc(u,m),u)
4666 ;; = log(jacobi_dc(u,m)+sqrt(m_1)*jacobi_sc(u,m))/sqrt(m_1), where m + m_1 = 1
4667 (defprop %jacobi_nc
4668 ((u m)
4669 ((mtimes simp)
4670 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m))
4671 ((rat simp) -1 2))
4672 ((%log simp)
4673 ((mplus simp) ((%jacobi_dc simp) u m)
4674 ((mtimes simp)
4675 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m))
4676 ((rat simp) 1 2))
4677 ((%jacobi_sc simp) u m)))))
4678 nil)
4679 integral)
4681 ;; A&S 16.24.9: integrate(jacobi_sc(u,m),u)
4682 ;; = log(jacobi_dc(u,m)+sqrt(m_1)*jacobi_nc(u,m))/sqrt(m_1), where m + m_1 = 1
4683 (defprop %jacobi_sc
4684 ((u m)
4685 ((mtimes simp)
4686 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m))
4687 ((rat simp) -1 2))
4688 ((%log simp)
4689 ((mplus simp) ((%jacobi_dc simp) u m)
4690 ((mtimes simp)
4691 ((mexpt simp) ((mplus simp) 1 ((mtimes simp) -1 m))
4692 ((rat simp) 1 2))
4693 ((%jacobi_nc simp) u m)))))
4694 nil)
4695 integral)
4697 ;; A&S 16.24.10: integrate(jacobi_ns(u,m),u)
4698 ;; = log(jacobi_ds(u,m)-jacobi_cs(u,m))
4699 (defprop %jacobi_ns
4700 ((u m)
4701 ((%log simp)
4702 ((mplus simp) ((mtimes simp) -1 ((%jacobi_cs simp) u m))
4703 ((%jacobi_ds simp) u m)))
4704 nil)
4705 integral)
4707 ;; integrate(jacobi_ds(u,m),u)
4709 ;; A&S 16.24.11 gives
4710 ;; log(jacobi_ds(u,m)-jacobi_cs(u,m))
4711 ;; but this does not pass some simple tests.
4713 ;; functions.wolfram.com 09.30.21.0001.01 gives
4714 ;; log((1-jacobi_cn(u,m))/jacobi_sn(u,m))
4716 (defprop %jacobi_ds
4717 ((u m)
4718 ((%log simp)
4719 ((mtimes simp)
4720 ((mplus simp) 1 ((mtimes simp) -1 ((%jacobi_cn simp) u m)))
4721 ((mexpt simp) ((%jacobi_sn simp) u m) -1)))
4722 nil)
4723 integral)
4725 ;; A&S 16.24.12: integrate(jacobi_cs(u,m),u) = log(jacobi_ns(u,m)-jacobi_ds(u,m))
4726 (defprop %jacobi_cs
4727 ((u m)
4728 ((%log simp)
4729 ((mplus simp) ((mtimes simp) -1 ((%jacobi_ds simp) u m))
4730 ((%jacobi_ns simp) u m)))
4731 nil)
4732 integral)
4734 ;; functions.wolfram.com 09.48.21.0001.01
4735 ;; integrate(inverse_jacobi_sn(u,m),u) =
4736 ;; inverse_jacobi_sn(u,m)*u
4737 ;; - log( jacobi_dn(inverse_jacobi_sn(u,m),m)
4738 ;; -sqrt(m)*jacobi_cn(inverse_jacobi_sn(u,m),m)) / sqrt(m)
4739 (defprop %inverse_jacobi_sn
4740 ((u m)
4741 ((mplus simp) ((mtimes simp) u ((%inverse_jacobi_sn simp) u m))
4742 ((mtimes simp) -1 ((mexpt simp) m ((rat simp) -1 2))
4743 ((%log simp)
4744 ((mplus simp)
4745 ((mtimes simp) -1 ((mexpt simp) m ((rat simp) 1 2))
4746 ((%jacobi_cn simp) ((%inverse_jacobi_sn simp) u m) m))
4747 ((%jacobi_dn simp) ((%inverse_jacobi_sn simp) u m) m)))))
4748 nil)
4749 integral)
4751 ;; functions.wolfram.com 09.38.21.0001.01
4752 ;; integrate(inverse_jacobi_cn(u,m),u) =
4753 ;; u*inverse_jacobi_cn(u,m)
4754 ;; -%i*log(%i*jacobi_dn(inverse_jacobi_cn(u,m),m)/sqrt(m)
4755 ;; -jacobi_sn(inverse_jacobi_cn(u,m),m))
4756 ;; /sqrt(m)
4757 (defprop %inverse_jacobi_cn
4758 ((u m)
4759 ((mplus simp) ((mtimes simp) u ((%inverse_jacobi_cn simp) u m))
4760 ((mtimes simp) -1 $%i ((mexpt simp) m ((rat simp) -1 2))
4761 ((%log simp)
4762 ((mplus simp)
4763 ((mtimes simp) $%i ((mexpt simp) m ((rat simp) -1 2))
4764 ((%jacobi_dn simp) ((%inverse_jacobi_cn simp) u m) m))
4765 ((mtimes simp) -1
4766 ((%jacobi_sn simp) ((%inverse_jacobi_cn simp) u m) m))))))
4767 nil)
4768 integral)
4770 ;; functions.wolfram.com 09.41.21.0001.01
4771 ;; integrate(inverse_jacobi_dn(u,m),u) =
4772 ;; u*inverse_jacobi_dn(u,m)
4773 ;; - %i*log(%i*jacobi_cn(inverse_jacobi_dn(u,m),m)
4774 ;; +jacobi_sn(inverse_jacobi_dn(u,m),m))
4775 (defprop %inverse_jacobi_dn
4776 ((u m)
4777 ((mplus simp) ((mtimes simp) u ((%inverse_jacobi_dn simp) u m))
4778 ((mtimes simp) -1 $%i
4779 ((%log simp)
4780 ((mplus simp)
4781 ((mtimes simp) $%i
4782 ((%jacobi_cn simp) ((%inverse_jacobi_dn simp) u m) m))
4783 ((%jacobi_sn simp) ((%inverse_jacobi_dn simp) u m) m)))))
4784 nil)
4785 integral)
4788 ;; Real and imaginary part for Jacobi elliptic functions.
4789 (defprop %jacobi_sn risplit-sn-cn-dn risplit-function)
4790 (defprop %jacobi_cn risplit-sn-cn-dn risplit-function)
4791 (defprop %jacobi_dn risplit-sn-cn-dn risplit-function)
4793 (defun risplit-sn-cn-dn (expr)
4794 (let* ((arg (second expr))
4795 (param (third expr)))
4796 ;; We only split on the argument, not the order
4797 (destructuring-bind (arg-r . arg-i)
4798 (risplit arg)
4799 (cond ((=0 arg-i)
4800 ;; Pure real
4801 (cons (take (first expr) arg-r param)
4804 (let* ((s (take '(%jacobi_sn) arg-r param))
4805 (c (take '(%jacobi_cn) arg-r param))
4806 (d (take '(%jacobi_dn) arg-r param))
4807 (s1 (take '(%jacobi_sn) arg-i (sub 1 param)))
4808 (c1 (take '(%jacobi_cn) arg-i (sub 1 param)))
4809 (d1 (take '(%jacobi_dn) arg-i (sub 1 param)))
4810 (den (add (mul c1 c1)
4811 (mul param
4812 (mul (mul s s)
4813 (mul s1 s1))))))
4814 ;; Let s = jacobi_sn(x,m)
4815 ;; c = jacobi_cn(x,m)
4816 ;; d = jacobi_dn(x,m)
4817 ;; s1 = jacobi_sn(y,1-m)
4818 ;; c1 = jacobi_cn(y,1-m)
4819 ;; d1 = jacobi_dn(y,1-m)
4820 (case (caar expr)
4821 (%jacobi_sn
4822 ;; A&S 16.21.1
4823 ;; jacobi_sn(x+%i*y,m) =
4825 ;; s*d1 + %i*c*d*s1*c1
4826 ;; -------------------
4827 ;; c1^2+m*s^2*s1^2
4829 (cons (div (mul s d1) den)
4830 (div (mul c (mul d (mul s1 c1)))
4831 den)))
4832 (%jacobi_cn
4833 ;; A&S 16.21.2
4835 ;; cn(x+%i_y, m) =
4837 ;; c*c1 - %i*s*d*s1*d1
4838 ;; -------------------
4839 ;; c1^2+m*s^2*s1^2
4840 (cons (div (mul c c1) den)
4841 (div (mul -1
4842 (mul s (mul d (mul s1 d1))))
4843 den)))
4844 (%jacobi_dn
4845 ;; A&S 16.21.3
4847 ;; dn(x+%i_y, m) =
4849 ;; d*c1*d1 - %i*m*s*c*s1
4850 ;; ---------------------
4851 ;; c1^2+m*s^2*s1^2
4852 (cons (div (mul d (mul c1 d1))
4853 den)
4854 (div (mul -1 (mul param (mul s (mul c s1))))
4855 den))))))))))