pygeodesy 24.3.24__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. PyGeodesy-24.3.24.dist-info/METADATA +272 -0
  2. PyGeodesy-24.3.24.dist-info/RECORD +115 -0
  3. PyGeodesy-24.3.24.dist-info/WHEEL +6 -0
  4. PyGeodesy-24.3.24.dist-info/top_level.txt +1 -0
  5. pygeodesy/LICENSE +21 -0
  6. pygeodesy/__init__.py +615 -0
  7. pygeodesy/__main__.py +103 -0
  8. pygeodesy/albers.py +867 -0
  9. pygeodesy/auxilats/_CX_4.py +218 -0
  10. pygeodesy/auxilats/_CX_6.py +314 -0
  11. pygeodesy/auxilats/_CX_8.py +475 -0
  12. pygeodesy/auxilats/__init__.py +54 -0
  13. pygeodesy/auxilats/__main__.py +86 -0
  14. pygeodesy/auxilats/auxAngle.py +548 -0
  15. pygeodesy/auxilats/auxDLat.py +302 -0
  16. pygeodesy/auxilats/auxDST.py +296 -0
  17. pygeodesy/auxilats/auxLat.py +848 -0
  18. pygeodesy/auxilats/auxily.py +272 -0
  19. pygeodesy/azimuthal.py +1150 -0
  20. pygeodesy/basics.py +892 -0
  21. pygeodesy/booleans.py +2031 -0
  22. pygeodesy/cartesianBase.py +1062 -0
  23. pygeodesy/clipy.py +704 -0
  24. pygeodesy/constants.py +516 -0
  25. pygeodesy/css.py +660 -0
  26. pygeodesy/datums.py +752 -0
  27. pygeodesy/deprecated/__init__.py +61 -0
  28. pygeodesy/deprecated/bases.py +40 -0
  29. pygeodesy/deprecated/classes.py +262 -0
  30. pygeodesy/deprecated/consterns.py +54 -0
  31. pygeodesy/deprecated/datum.py +40 -0
  32. pygeodesy/deprecated/functions.py +375 -0
  33. pygeodesy/deprecated/nvector.py +48 -0
  34. pygeodesy/deprecated/rhumbBase.py +32 -0
  35. pygeodesy/deprecated/rhumbaux.py +33 -0
  36. pygeodesy/deprecated/rhumbsolve.py +33 -0
  37. pygeodesy/deprecated/rhumbx.py +33 -0
  38. pygeodesy/dms.py +986 -0
  39. pygeodesy/ecef.py +1348 -0
  40. pygeodesy/elevations.py +279 -0
  41. pygeodesy/ellipsoidalBase.py +1224 -0
  42. pygeodesy/ellipsoidalBaseDI.py +913 -0
  43. pygeodesy/ellipsoidalExact.py +343 -0
  44. pygeodesy/ellipsoidalGeodSolve.py +343 -0
  45. pygeodesy/ellipsoidalKarney.py +403 -0
  46. pygeodesy/ellipsoidalNvector.py +685 -0
  47. pygeodesy/ellipsoidalVincenty.py +590 -0
  48. pygeodesy/ellipsoids.py +2476 -0
  49. pygeodesy/elliptic.py +1198 -0
  50. pygeodesy/epsg.py +243 -0
  51. pygeodesy/errors.py +804 -0
  52. pygeodesy/etm.py +1190 -0
  53. pygeodesy/fmath.py +1013 -0
  54. pygeodesy/formy.py +1818 -0
  55. pygeodesy/frechet.py +865 -0
  56. pygeodesy/fstats.py +760 -0
  57. pygeodesy/fsums.py +1898 -0
  58. pygeodesy/gars.py +358 -0
  59. pygeodesy/geodesicw.py +581 -0
  60. pygeodesy/geodesicx/_C4_24.py +1699 -0
  61. pygeodesy/geodesicx/_C4_27.py +2395 -0
  62. pygeodesy/geodesicx/_C4_30.py +3301 -0
  63. pygeodesy/geodesicx/__init__.py +48 -0
  64. pygeodesy/geodesicx/__main__.py +91 -0
  65. pygeodesy/geodesicx/gx.py +1382 -0
  66. pygeodesy/geodesicx/gxarea.py +535 -0
  67. pygeodesy/geodesicx/gxbases.py +154 -0
  68. pygeodesy/geodesicx/gxline.py +669 -0
  69. pygeodesy/geodsolve.py +426 -0
  70. pygeodesy/geohash.py +914 -0
  71. pygeodesy/geoids.py +1884 -0
  72. pygeodesy/hausdorff.py +892 -0
  73. pygeodesy/heights.py +1155 -0
  74. pygeodesy/interns.py +687 -0
  75. pygeodesy/iters.py +545 -0
  76. pygeodesy/karney.py +919 -0
  77. pygeodesy/ktm.py +633 -0
  78. pygeodesy/latlonBase.py +1766 -0
  79. pygeodesy/lazily.py +960 -0
  80. pygeodesy/lcc.py +684 -0
  81. pygeodesy/ltp.py +1107 -0
  82. pygeodesy/ltpTuples.py +1563 -0
  83. pygeodesy/mgrs.py +721 -0
  84. pygeodesy/named.py +1324 -0
  85. pygeodesy/namedTuples.py +683 -0
  86. pygeodesy/nvectorBase.py +695 -0
  87. pygeodesy/osgr.py +781 -0
  88. pygeodesy/points.py +1686 -0
  89. pygeodesy/props.py +628 -0
  90. pygeodesy/resections.py +1048 -0
  91. pygeodesy/rhumb/__init__.py +46 -0
  92. pygeodesy/rhumb/aux_.py +397 -0
  93. pygeodesy/rhumb/bases.py +1148 -0
  94. pygeodesy/rhumb/ekx.py +563 -0
  95. pygeodesy/rhumb/solve.py +572 -0
  96. pygeodesy/simplify.py +647 -0
  97. pygeodesy/solveBase.py +472 -0
  98. pygeodesy/sphericalBase.py +724 -0
  99. pygeodesy/sphericalNvector.py +1264 -0
  100. pygeodesy/sphericalTrigonometry.py +1447 -0
  101. pygeodesy/streprs.py +627 -0
  102. pygeodesy/trf.py +2079 -0
  103. pygeodesy/triaxials.py +1484 -0
  104. pygeodesy/units.py +969 -0
  105. pygeodesy/unitsBase.py +349 -0
  106. pygeodesy/ups.py +538 -0
  107. pygeodesy/utily.py +1231 -0
  108. pygeodesy/utm.py +762 -0
  109. pygeodesy/utmups.py +318 -0
  110. pygeodesy/utmupsBase.py +517 -0
  111. pygeodesy/vector2d.py +785 -0
  112. pygeodesy/vector3d.py +968 -0
  113. pygeodesy/vector3dBase.py +1049 -0
  114. pygeodesy/webmercator.py +383 -0
  115. pygeodesy/wgrs.py +439 -0
pygeodesy/elliptic.py ADDED
@@ -0,0 +1,1198 @@
1
+
2
+ # -*- coding: utf-8 -*-
3
+
4
+ u'''I{Karney}'s elliptic functions and integrals.
5
+
6
+ Class L{Elliptic} transcoded from I{Charles Karney}'s C++ class U{EllipticFunction
7
+ <https://GeographicLib.SourceForge.io/C++/doc/classGeographicLib_1_1EllipticFunction.html>}
8
+ to pure Python, including symmetric integrals L{Elliptic.fRC}, L{Elliptic.fRD},
9
+ L{Elliptic.fRF}, L{Elliptic.fRG} and L{Elliptic.fRJ} as C{static methods}.
10
+
11
+ Python method names follow the C++ member functions, I{except}:
12
+
13
+ - member functions I{without arguments} are mapped to Python properties
14
+ prefixed with C{"c"}, for example C{E()} is property C{cE},
15
+
16
+ - member functions with 1 or 3 arguments are renamed to Python methods
17
+ starting with an C{"f"}, example C{E(psi)} to C{fE(psi)} and C{E(sn,
18
+ cn, dn)} to C{fE(sn, cn, dn)},
19
+
20
+ - other Python method names conventionally start with a lower-case
21
+ letter or an underscore if private.
22
+
23
+ Following is a copy of I{Karney}'s U{EllipticFunction.hpp
24
+ <https://GeographicLib.SourceForge.io/C++/doc/EllipticFunction_8hpp_source.html>}
25
+ file C{Header}.
26
+
27
+ Copyright (C) U{Charles Karney<mailto:Karney@Alum.MIT.edu>} (2008-2023)
28
+ and licensed under the MIT/X11 License. For more information, see the
29
+ U{GeographicLib<https://GeographicLib.SourceForge.io>} documentation.
30
+
31
+ B{Elliptic integrals and functions.}
32
+
33
+ This provides the elliptic functions and integrals needed for
34
+ C{Ellipsoid}, C{GeodesicExact}, and C{TransverseMercatorExact}. Two
35
+ categories of function are provided:
36
+
37
+ - functions to compute U{symmetric elliptic integrals
38
+ <https://DLMF.NIST.gov/19.16.i>}
39
+
40
+ - methods to compute U{Legrendre's elliptic integrals
41
+ <https://DLMF.NIST.gov/19.2.ii>} and U{Jacobi elliptic
42
+ functions<https://DLMF.NIST.gov/22.2>}.
43
+
44
+ In the latter case, an object is constructed giving the modulus
45
+ C{k} (and optionally the parameter C{alpha}). The modulus (and
46
+ parameter) are always passed as squares which allows C{k} to be
47
+ pure imaginary. (Confusingly, Abramowitz and Stegun call C{m = k**2}
48
+ the "parameter" and C{n = alpha**2} the "characteristic".)
49
+
50
+ In geodesic applications, it is convenient to separate the incomplete
51
+ integrals into secular and periodic components, e.g.
52
+
53
+ I{C{E(phi, k) = (2 E(k) / pi) [ phi + delta E(phi, k) ]}}
54
+
55
+ where I{C{delta E(phi, k)}} is an odd periodic function with
56
+ period I{C{pi}}.
57
+
58
+ The computation of the elliptic integrals uses the algorithms given
59
+ in U{B. C. Carlson, Computation of real or complex elliptic integrals
60
+ <https://DOI.org/10.1007/BF02198293>} (also available U{here
61
+ <https://ArXiv.org/pdf/math/9409227.pdf>}), Numerical Algorithms 10,
62
+ 13--26 (1995) with the additional optimizations given U{here
63
+ <https://DLMF.NIST.gov/19.36.i>}.
64
+
65
+ The computation of the Jacobi elliptic functions uses the algorithm
66
+ given in U{R. Bulirsch, Numerical Calculation of Elliptic Integrals
67
+ and Elliptic Functions<https://DOI.org/10.1007/BF01397975>},
68
+ Numerische Mathematik 7, 78--90 (1965).
69
+
70
+ The notation follows U{NIST Digital Library of Mathematical Functions
71
+ <https://DLMF.NIST.gov>} chapters U{19<https://DLMF.NIST.gov/19>} and
72
+ U{22<https://DLMF.NIST.gov/22>}.
73
+ '''
74
+ # make sure int/int division yields float quotient, see .basics
75
+ from __future__ import division as _; del _ # PYCHOK semicolon
76
+
77
+ from pygeodesy.basics import copysign0, map2, neg, neg_
78
+ from pygeodesy.constants import EPS, INF, NAN, PI, PI_2, PI_4, \
79
+ _EPStol as _TolJAC, _0_0, _1_64th, \
80
+ _0_25, _0_5, _1_0, _2_0, _N_2_0, \
81
+ _3_0, _4_0, _6_0, _8_0, _180_0, \
82
+ _360_0, _over
83
+ # from pygeodesy.errors import _ValueError # from .fmath
84
+ from pygeodesy.fmath import fdot, hypot1, zqrt, _ValueError
85
+ from pygeodesy.fsums import Fsum, _sum, _ALL_LAZY
86
+ from pygeodesy.interns import NN, _delta_, _DOT_, _dunder_nameof, _f_, \
87
+ _invalid_, _invokation_, _negative_, _SPACE_
88
+ from pygeodesy.karney import _K_2_0, _norm180, _signBit, _sincos2
89
+ # from pygeodesy.lazily import _ALL_LAZY # from .fsums
90
+ from pygeodesy.named import _Named, _NamedTuple, Fmt, unstr
91
+ from pygeodesy.props import _allPropertiesOf_n, Property_RO, _update_all
92
+ # from pygeodesy.streprs import Fmt, unstr # from .named
93
+ from pygeodesy.units import Scalar, Scalar_
94
+ # from pygeodesy.utily import sincos2 as _sincos2 # from .karney
95
+
96
+ from math import asinh, atan, atan2, ceil, cosh, fabs, floor, \
97
+ radians, sin, sqrt, tanh
98
+
99
+ __all__ = _ALL_LAZY.elliptic
100
+ __version__ = '24.03.22'
101
+
102
+ _TolRD = zqrt(EPS * 0.002)
103
+ _TolRF = zqrt(EPS * 0.030)
104
+ _TolRG0 = _TolJAC * 2.7
105
+ _TRIPS = 21 # Max depth, 7 might be sufficient
106
+
107
+
108
+ class _Cs(object):
109
+ '''(INTERAL) Complete integrals cache.
110
+ '''
111
+ def __init__(self, **kwds):
112
+ self.__dict__ = kwds
113
+
114
+
115
+ class _D(list):
116
+ '''(INTERNAL) Deferred C{Fsum}.
117
+ '''
118
+ def __call__(self, s):
119
+ try: # Fsum *= s
120
+ return Fsum(*self).fmul(s)
121
+ except ValueError: # Fsum(NAN) exception
122
+ return _sum(self) * s
123
+
124
+ def __iadd__(self, x):
125
+ list.append(self, x)
126
+ return self
127
+
128
+
129
+ class Elliptic(_Named):
130
+ '''Elliptic integrals and functions.
131
+
132
+ @see: I{Karney}'s U{Detailed Description<https://GeographicLib.SourceForge.io/
133
+ C++/doc/classGeographicLib_1_1EllipticFunction.html#details>}.
134
+ '''
135
+ # _alpha2 = 0
136
+ # _alphap2 = 0
137
+ # _eps = EPS
138
+ # _k2 = 0
139
+ # _kp2 = 0
140
+
141
+ def __init__(self, k2=0, alpha2=0, kp2=None, alphap2=None, name=NN):
142
+ '''Constructor, specifying the C{modulus} and C{parameter}.
143
+
144
+ @kwarg name: Optional name (C{str}).
145
+
146
+ @see: Method L{Elliptic.reset} for further details.
147
+
148
+ @note: If only elliptic integrals of the first and second kinds
149
+ are needed, use C{B{alpha2}=0}, the default value. In
150
+ that case, we have C{Π(φ, 0, k) = F(φ, k), G(φ, 0, k) =
151
+ E(φ, k)} and C{H(φ, 0, k) = F(φ, k) - D(φ, k)}.
152
+ '''
153
+ self.reset(k2=k2, alpha2=alpha2, kp2=kp2, alphap2=alphap2)
154
+
155
+ if name:
156
+ self.name = name
157
+
158
+ @Property_RO
159
+ def alpha2(self):
160
+ '''Get α^2, the square of the parameter (C{float}).
161
+ '''
162
+ return self._alpha2
163
+
164
+ @Property_RO
165
+ def alphap2(self):
166
+ '''Get α'^2, the square of the complementary parameter (C{float}).
167
+ '''
168
+ return self._alphap2
169
+
170
+ @Property_RO
171
+ def cD(self):
172
+ '''Get Jahnke's complete integral C{D(k)} (C{float}),
173
+ U{defined<https://DLMF.NIST.gov/19.2.E6>}.
174
+ '''
175
+ return self._cDEKEeps.cD
176
+
177
+ @Property_RO
178
+ def _cDEKEeps(self):
179
+ '''(INTERNAL) Get the complete integrals D, E, K and KE plus C{eps}.
180
+ '''
181
+ k2, kp2 = self.k2, self.kp2
182
+ if k2:
183
+ if kp2:
184
+ try:
185
+ self._iteration = 0
186
+ # D(k) = (K(k) - E(k))/k2, Carlson eq.4.3
187
+ # <https://DLMF.NIST.gov/19.25.E1>
188
+ D = _RD(self, _0_0, kp2, _1_0, _3_0)
189
+ cD = float(D)
190
+ # Complete elliptic integral E(k), Carlson eq. 4.2
191
+ # <https://DLMF.NIST.gov/19.25.E1>
192
+ cE = _rG2(self, kp2, _1_0, PI_=PI_2)
193
+ # Complete elliptic integral K(k), Carlson eq. 4.1
194
+ # <https://DLMF.NIST.gov/19.25.E1>
195
+ cK = _rF2(self, kp2, _1_0)
196
+ cKE = float(D.fmul(k2))
197
+ eps = k2 / (sqrt(kp2) + _1_0)**2
198
+
199
+ except Exception as e:
200
+ raise _ellipticError(self.reset, k2=k2, kp2=kp2, cause=e)
201
+ else:
202
+ cD = cK = cKE = INF
203
+ cE = _1_0
204
+ eps = k2
205
+ else:
206
+ cD = PI_4
207
+ cE = cK = PI_2
208
+ cKE = _0_0 # k2 * cD
209
+ eps = EPS
210
+
211
+ return _Cs(cD=cD, cE=cE, cK=cK, cKE=cKE, eps=eps)
212
+
213
+ @Property_RO
214
+ def cE(self):
215
+ '''Get the complete integral of the second kind C{E(k)}
216
+ (C{float}), U{defined<https://DLMF.NIST.gov/19.2.E5>}.
217
+ '''
218
+ return self._cDEKEeps.cE
219
+
220
+ @Property_RO
221
+ def cG(self):
222
+ '''Get Legendre's complete geodesic longitude integral
223
+ C{G(α^2, k)} (C{float}).
224
+ '''
225
+ return self._cGHPi.cG
226
+
227
+ @Property_RO
228
+ def _cGHPi(self):
229
+ '''(INTERNAL) Get the complete integrals G, H and Pi.
230
+ '''
231
+ alpha2, alphap2, kp2 = self.alpha2, self.alphap2, self.kp2
232
+ try:
233
+ self._iteration = 0
234
+ if alpha2:
235
+ if alphap2:
236
+ if kp2: # <https://DLMF.NIST.gov/19.25.E2>
237
+ cK = self.cK
238
+ Rj = _RJ(self, _0_0, kp2, _1_0, alphap2, _3_0)
239
+ cG = float(Rj * (alpha2 - self.k2) + cK) # G(alpha2, k)
240
+ cH = -float(Rj * alphap2 - cK) # H(alpha2, k)
241
+ cPi = float(Rj * alpha2 + cK) # Pi(alpha2, k)
242
+ else:
243
+ cG = cH = _rC(self, _1_0, alphap2)
244
+ cPi = INF # XXX or NAN?
245
+ else:
246
+ cG = cH = cPi = INF # XXX or NAN?
247
+ else:
248
+ cG, cPi = self.cE, self.cK
249
+ # H = K - D but this involves large cancellations if k2 is near 1.
250
+ # So write (for alpha2 = 0)
251
+ # H = int(cos(phi)**2 / sqrt(1-k2 * sin(phi)**2), phi, 0, pi/2)
252
+ # = 1 / sqrt(1-k2) * int(sin(phi)**2 / sqrt(1-k2/kp2 * sin(phi)**2,...)
253
+ # = 1 / kp * D(i * k/kp)
254
+ # and use D(k) = RD(0, kp2, 1) / 3, so
255
+ # H = 1/kp * RD(0, 1/kp2, 1) / 3
256
+ # = kp2 * RD(0, 1, kp2) / 3
257
+ # using <https://DLMF.NIST.gov/19.20.E18>. Equivalently
258
+ # RF(x, 1) - RD(0, x, 1) / 3 = x * RD(0, 1, x) / 3 for x > 0
259
+ # For k2 = 1 and alpha2 = 0, we have
260
+ # H = int(cos(phi),...) = 1
261
+ cH = float(_RD(self, _0_0, _1_0, kp2, _3_0 / kp2)) if kp2 else _1_0
262
+
263
+ except Exception as e:
264
+ raise _ellipticError(self.reset, kp2=kp2, alpha2 =alpha2,
265
+ alphap2=alphap2, cause=e)
266
+ return _Cs(cG=cG, cH=cH, cPi=cPi)
267
+
268
+ @Property_RO
269
+ def cH(self):
270
+ '''Get Cayley's complete geodesic longitude difference integral
271
+ C{H(α^2, k)} (C{float}).
272
+ '''
273
+ return self._cGHPi.cH
274
+
275
+ @Property_RO
276
+ def cK(self):
277
+ '''Get the complete integral of the first kind C{K(k)}
278
+ (C{float}), U{defined<https://DLMF.NIST.gov/19.2.E4>}.
279
+ '''
280
+ return self._cDEKEeps.cK
281
+
282
+ @Property_RO
283
+ def cKE(self):
284
+ '''Get the difference between the complete integrals of the
285
+ first and second kinds, C{K(k) − E(k)} (C{float}).
286
+ '''
287
+ return self._cDEKEeps.cKE
288
+
289
+ @Property_RO
290
+ def cPi(self):
291
+ '''Get the complete integral of the third kind C{Pi(α^2, k)}
292
+ (C{float}), U{defined<https://DLMF.NIST.gov/19.2.E7>}.
293
+ '''
294
+ return self._cGHPi.cPi
295
+
296
+ def deltaD(self, sn, cn, dn):
297
+ '''Jahnke's periodic incomplete elliptic integral.
298
+
299
+ @arg sn: sin(φ).
300
+ @arg cn: cos(φ).
301
+ @arg dn: sqrt(1 − k2 * sin(2φ)).
302
+
303
+ @return: Periodic function π D(φ, k) / (2 D(k)) - φ (C{float}).
304
+
305
+ @raise EllipticError: Invalid invokation or no convergence.
306
+ '''
307
+ return _deltaX(sn, cn, dn, self.cD, self.fD)
308
+
309
+ def deltaE(self, sn, cn, dn):
310
+ '''The periodic incomplete integral of the second kind.
311
+
312
+ @arg sn: sin(φ).
313
+ @arg cn: cos(φ).
314
+ @arg dn: sqrt(1 − k2 * sin(2φ)).
315
+
316
+ @return: Periodic function π E(φ, k) / (2 E(k)) - φ (C{float}).
317
+
318
+ @raise EllipticError: Invalid invokation or no convergence.
319
+ '''
320
+ return _deltaX(sn, cn, dn, self.cE, self.fE)
321
+
322
+ def deltaEinv(self, stau, ctau):
323
+ '''The periodic inverse of the incomplete integral of the second kind.
324
+
325
+ @arg stau: sin(τ)
326
+ @arg ctau: cos(τ)
327
+
328
+ @return: Periodic function E^−1(τ (2 E(k)/π), k) - τ (C{float}).
329
+
330
+ @raise EllipticError: No convergence.
331
+ '''
332
+ try:
333
+ if _signBit(ctau): # pi periodic
334
+ stau, ctau = neg_(stau, ctau)
335
+ t = atan2(stau, ctau)
336
+ return self._Einv(t * self.cE / PI_2) - t
337
+
338
+ except Exception as e:
339
+ raise _ellipticError(self.deltaEinv, stau, ctau, cause=e)
340
+
341
+ def deltaF(self, sn, cn, dn):
342
+ '''The periodic incomplete integral of the first kind.
343
+
344
+ @arg sn: sin(φ).
345
+ @arg cn: cos(φ).
346
+ @arg dn: sqrt(1 − k2 * sin(2φ)).
347
+
348
+ @return: Periodic function π F(φ, k) / (2 K(k)) - φ (C{float}).
349
+
350
+ @raise EllipticError: Invalid invokation or no convergence.
351
+ '''
352
+ return _deltaX(sn, cn, dn, self.cK, self.fF)
353
+
354
+ def deltaG(self, sn, cn, dn):
355
+ '''Legendre's periodic geodesic longitude integral.
356
+
357
+ @arg sn: sin(φ).
358
+ @arg cn: cos(φ).
359
+ @arg dn: sqrt(1 − k2 * sin(2φ)).
360
+
361
+ @return: Periodic function π G(φ, k) / (2 G(k)) - φ (C{float}).
362
+
363
+ @raise EllipticError: Invalid invokation or no convergence.
364
+ '''
365
+ return _deltaX(sn, cn, dn, self.cG, self.fG)
366
+
367
+ def deltaH(self, sn, cn, dn):
368
+ '''Cayley's periodic geodesic longitude difference integral.
369
+
370
+ @arg sn: sin(φ).
371
+ @arg cn: cos(φ).
372
+ @arg dn: sqrt(1 − k2 * sin(2φ)).
373
+
374
+ @return: Periodic function π H(φ, k) / (2 H(k)) - φ (C{float}).
375
+
376
+ @raise EllipticError: Invalid invokation or no convergence.
377
+ '''
378
+ return _deltaX(sn, cn, dn, self.cH, self.fH)
379
+
380
+ def deltaPi(self, sn, cn, dn):
381
+ '''The periodic incomplete integral of the third kind.
382
+
383
+ @arg sn: sin(φ).
384
+ @arg cn: cos(φ).
385
+ @arg dn: sqrt(1 − k2 * sin(2φ)).
386
+
387
+ @return: Periodic function π Π(φ, α2, k) / (2 Π(α2, k)) - φ
388
+ (C{float}).
389
+
390
+ @raise EllipticError: Invalid invokation or no convergence.
391
+ '''
392
+ return _deltaX(sn, cn, dn, self.cPi, self.fPi)
393
+
394
+ def _Einv(self, x):
395
+ '''(INTERNAL) Helper for C{.deltaEinv} and C{.fEinv}.
396
+ '''
397
+ E2 = self.cE * _2_0
398
+ n = floor(x / E2 + _0_5)
399
+ r = x - E2 * n # r in [-cE, cE)
400
+ # linear approximation
401
+ phi = PI * r / E2 # phi in [-PI_2, PI_2)
402
+ Phi = Fsum(phi)
403
+ # first order correction
404
+ phi = Phi.fsum_(self.eps * sin(phi * _2_0) / _N_2_0)
405
+ # For kp2 close to zero use asin(r / cE) or J. P. Boyd,
406
+ # Applied Math. and Computation 218, 7005-7013 (2012)
407
+ # <https://DOI.org/10.1016/j.amc.2011.12.021>
408
+ _Phi2, self._iteration = Phi.fsum2_, 0 # aggregate
409
+ for i in range(1, _TRIPS): # GEOGRAPHICLIB_PANIC
410
+ sn, cn, dn = self._sncndn3(phi)
411
+ if dn:
412
+ sn = self.fE(sn, cn, dn)
413
+ phi, d = _Phi2((r - sn) / dn)
414
+ else: # PYCHOK no cover
415
+ d = _0_0 # XXX continue?
416
+ if fabs(d) < _TolJAC: # 3-4 trips
417
+ _iterations(self, i)
418
+ break
419
+ else: # PYCHOK no cover
420
+ raise _convergenceError(d, _TolJAC)
421
+ return Phi.fsum_(n * PI) if n else phi
422
+
423
+ @Property_RO
424
+ def eps(self):
425
+ '''Get epsilon (C{float}).
426
+ '''
427
+ return self._cDEKEeps.eps
428
+
429
+ def fD(self, phi_or_sn, cn=None, dn=None):
430
+ '''Jahnke's incomplete elliptic integral in terms of
431
+ Jacobi elliptic functions.
432
+
433
+ @arg phi_or_sn: φ or sin(φ).
434
+ @kwarg cn: C{None} or cos(φ).
435
+ @kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
436
+
437
+ @return: D(φ, k) as though φ ∈ (−π, π] (C{float}),
438
+ U{defined<https://DLMF.NIST.gov/19.2.E4>}.
439
+
440
+ @raise EllipticError: Invalid invokation or no convergence.
441
+ '''
442
+ def _fD(sn, cn, dn):
443
+ r = fabs(sn)**3
444
+ if r:
445
+ r = float(_RD(self, cn**2, dn**2, _1_0, _3_0 / r))
446
+ return r
447
+
448
+ return self._fXf(phi_or_sn, cn, dn, self.cD,
449
+ self.deltaD, _fD)
450
+
451
+ def fDelta(self, sn, cn):
452
+ '''The C{Delta} amplitude function.
453
+
454
+ @arg sn: sin(φ).
455
+ @arg cn: cos(φ).
456
+
457
+ @return: sqrt(1 − k2 * sin(2φ)) (C{float}).
458
+ '''
459
+ try:
460
+ k2 = self.k2
461
+ s = (self.kp2 + cn**2 * k2) if k2 > 0 else (
462
+ (_1_0 - sn**2 * k2) if k2 < 0 else self.kp2)
463
+ return sqrt(s) if s else _0_0
464
+
465
+ except Exception as e:
466
+ raise _ellipticError(self.fDelta, sn, cn, k2=k2, cause=e)
467
+
468
+ def fE(self, phi_or_sn, cn=None, dn=None):
469
+ '''The incomplete integral of the second kind in terms of
470
+ Jacobi elliptic functions.
471
+
472
+ @arg phi_or_sn: φ or sin(φ).
473
+ @kwarg cn: C{None} or cos(φ).
474
+ @kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
475
+
476
+ @return: E(φ, k) as though φ ∈ (−π, π] (C{float}),
477
+ U{defined<https://DLMF.NIST.gov/19.2.E5>}.
478
+
479
+ @raise EllipticError: Invalid invokation or no convergence.
480
+ '''
481
+ def _fE(sn, cn, dn):
482
+ '''(INTERNAL) Core of C{.fE}.
483
+ '''
484
+ if sn:
485
+ sn2, cn2, dn2 = sn**2, cn**2, dn**2
486
+ kp2, k2 = self.kp2, self.k2
487
+ if k2 <= 0: # Carlson, eq. 4.6, <https://DLMF.NIST.gov/19.25.E9>
488
+ Ei = _RF3(self, cn2, dn2, _1_0)
489
+ if k2:
490
+ Ei -= _RD(self, cn2, dn2, _1_0, _3over(k2, sn2))
491
+ elif kp2 >= 0: # k2 > 0, <https://DLMF.NIST.gov/19.25.E10>
492
+ Ei = _over(k2 * fabs(cn), dn) # float
493
+ if kp2:
494
+ Ei += (_RD( self, cn2, _1_0, dn2, _3over(k2, sn2)) +
495
+ _RF3(self, cn2, dn2, _1_0)) * kp2
496
+ else: # kp2 < 0, <https://DLMF.NIST.gov/19.25.E11>
497
+ Ei = _over(dn, fabs(cn))
498
+ Ei -= _RD(self, dn2, _1_0, cn2, _3over(kp2, sn2))
499
+ Ei *= fabs(sn)
500
+ ei = float(Ei)
501
+ else: # PYCHOK no cover
502
+ ei = _0_0
503
+ return ei
504
+
505
+ return self._fXf(phi_or_sn, cn, dn, self.cE,
506
+ self.deltaE, _fE)
507
+
508
+ def fEd(self, deg):
509
+ '''The incomplete integral of the second kind with
510
+ the argument given in C{degrees}.
511
+
512
+ @arg deg: Angle (C{degrees}).
513
+
514
+ @return: E(π B{C{deg}} / 180, k) (C{float}).
515
+
516
+ @raise EllipticError: No convergence.
517
+ '''
518
+ if _K_2_0:
519
+ e = round((deg - _norm180(deg)) / _360_0)
520
+ elif fabs(deg) < _180_0:
521
+ e = _0_0
522
+ else:
523
+ e = ceil(deg / _360_0 - _0_5)
524
+ deg -= e * _360_0
525
+ return self.fE(radians(deg)) + e * self.cE * _4_0
526
+
527
+ def fEinv(self, x):
528
+ '''The inverse of the incomplete integral of the second kind.
529
+
530
+ @arg x: Argument (C{float}).
531
+
532
+ @return: φ = 1 / E(B{C{x}}, k), such that E(φ, k) = B{C{x}}
533
+ (C{float}).
534
+
535
+ @raise EllipticError: No convergence.
536
+ '''
537
+ try:
538
+ return self._Einv(x)
539
+ except Exception as e:
540
+ raise _ellipticError(self.fEinv, x, cause=e)
541
+
542
+ def fF(self, phi_or_sn, cn=None, dn=None):
543
+ '''The incomplete integral of the first kind in terms of
544
+ Jacobi elliptic functions.
545
+
546
+ @arg phi_or_sn: φ or sin(φ).
547
+ @kwarg cn: C{None} or cos(φ).
548
+ @kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
549
+
550
+ @return: F(φ, k) as though φ ∈ (−π, π] (C{float}),
551
+ U{defined<https://DLMF.NIST.gov/19.2.E4>}.
552
+
553
+ @raise EllipticError: Invalid invokation or no convergence.
554
+ '''
555
+ def _fF(sn, cn, dn):
556
+ r = fabs(sn)
557
+ if r:
558
+ r = float(_RF3(self, cn**2, dn**2, _1_0).fmul(r))
559
+ return r
560
+
561
+ return self._fXf(phi_or_sn, cn, dn, self.cK,
562
+ self.deltaF, _fF)
563
+
564
+ def fG(self, phi_or_sn, cn=None, dn=None):
565
+ '''Legendre's geodesic longitude integral in terms of
566
+ Jacobi elliptic functions.
567
+
568
+ @arg phi_or_sn: φ or sin(φ).
569
+ @kwarg cn: C{None} or cos(φ).
570
+ @kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
571
+
572
+ @return: G(φ, k) as though φ ∈ (−π, π] (C{float}).
573
+
574
+ @raise EllipticError: Invalid invokation or no convergence.
575
+
576
+ @note: Legendre expresses the longitude of a point on the
577
+ geodesic in terms of this combination of elliptic
578
+ integrals in U{Exercices de Calcul Intégral, Vol 1
579
+ (1811), p 181<https://Books.Google.com/books?id=
580
+ riIOAAAAQAAJ&pg=PA181>}.
581
+
582
+ @see: U{Geodesics in terms of elliptic integrals<https://
583
+ GeographicLib.SourceForge.io/C++/doc/geodesic.html#geodellip>}
584
+ for the expression for the longitude in terms of this function.
585
+ '''
586
+ return self._fXa(phi_or_sn, cn, dn, self.alpha2 - self.k2,
587
+ self.cG, self.deltaG)
588
+
589
+ def fH(self, phi_or_sn, cn=None, dn=None):
590
+ '''Cayley's geodesic longitude difference integral in terms of
591
+ Jacobi elliptic functions.
592
+
593
+ @arg phi_or_sn: φ or sin(φ).
594
+ @kwarg cn: C{None} or cos(φ).
595
+ @kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
596
+
597
+ @return: H(φ, k) as though φ ∈ (−π, π] (C{float}).
598
+
599
+ @raise EllipticError: Invalid invokation or no convergence.
600
+
601
+ @note: Cayley expresses the longitude difference of a point
602
+ on the geodesic in terms of this combination of
603
+ elliptic integrals in U{Phil. Mag. B{40} (1870), p 333
604
+ <https://Books.Google.com/books?id=Zk0wAAAAIAAJ&pg=PA333>}.
605
+
606
+ @see: U{Geodesics in terms of elliptic integrals<https://
607
+ GeographicLib.SourceForge.io/C++/doc/geodesic.html#geodellip>}
608
+ for the expression for the longitude in terms of this function.
609
+ '''
610
+ return self._fXa(phi_or_sn, cn, dn, -self.alphap2,
611
+ self.cH, self.deltaH)
612
+
613
+ def fPi(self, phi_or_sn, cn=None, dn=None):
614
+ '''The incomplete integral of the third kind in terms of
615
+ Jacobi elliptic functions.
616
+
617
+ @arg phi_or_sn: φ or sin(φ).
618
+ @kwarg cn: C{None} or cos(φ).
619
+ @kwarg dn: C{None} or sqrt(1 − k2 * sin(2φ)).
620
+
621
+ @return: Π(φ, α2, k) as though φ ∈ (−π, π] (C{float}).
622
+
623
+ @raise EllipticError: Invalid invokation or no convergence.
624
+ '''
625
+ if dn is None and cn is not None: # and isscalar(phi_or_sn)
626
+ dn = self.fDelta(phi_or_sn, cn) # in .triaxial
627
+ return self._fXa(phi_or_sn, cn, dn, self.alpha2,
628
+ self.cPi, self.deltaPi)
629
+
630
+ def _fXa(self, phi_or_sn, cn, dn, aX, cX, deltaX):
631
+ '''(INTERNAL) Helper for C{.fG}, C{.fH} and C{.fPi}.
632
+ '''
633
+ def _fX(sn, cn, dn):
634
+ if sn:
635
+ cn2, dn2 = cn**2, dn**2
636
+ R = _RF3(self, cn2, dn2, _1_0)
637
+ if aX:
638
+ sn2 = sn**2
639
+ p = sn2 * self.alphap2 + cn2
640
+ R += _RJ(self, cn2, dn2, _1_0, p, _3over(aX, sn2))
641
+ R *= fabs(sn)
642
+ r = float(R)
643
+ else: # PYCHOK no cover
644
+ r = _0_0
645
+ return r
646
+
647
+ return self._fXf(phi_or_sn, cn, dn, cX, deltaX, _fX)
648
+
649
+ def _fXf(self, phi_or_sn, cn, dn, cX, deltaX, fX):
650
+ '''(INTERNAL) Helper for C{.fD}, C{.fE}, C{.fF} and C{._fXa}.
651
+ '''
652
+ self._iteration = 0 # aggregate
653
+ phi = sn = phi_or_sn
654
+ if cn is dn is None: # fX(phi) call
655
+ sn, cn, dn = self._sncndn3(phi)
656
+ if fabs(phi) >= PI:
657
+ return (deltaX(sn, cn, dn) + phi) * cX / PI_2
658
+ # fall through
659
+ elif cn is None or dn is None:
660
+ n = NN(_f_, deltaX.__name__[5:])
661
+ raise _ellipticError(n, sn, cn, dn)
662
+
663
+ if _signBit(cn): # enforce usual trig-like symmetries
664
+ xi = cX * _2_0 - fX(sn, cn, dn)
665
+ else:
666
+ xi = fX(sn, cn, dn) if cn > 0 else cX
667
+ return copysign0(xi, sn)
668
+
669
+ @Property_RO
670
+ def k2(self):
671
+ '''Get k^2, the square of the modulus (C{float}).
672
+ '''
673
+ return self._k2
674
+
675
+ @Property_RO
676
+ def kp2(self):
677
+ '''Get k'^2, the square of the complementary modulus (C{float}).
678
+ '''
679
+ return self._kp2
680
+
681
+ def reset(self, k2=0, alpha2=0, kp2=None, alphap2=None): # MCCABE 13
682
+ '''Reset the modulus, parameter and the complementaries.
683
+
684
+ @kwarg k2: Modulus squared (C{float}, NINF <= k^2 <= 1).
685
+ @kwarg alpha2: Parameter squared (C{float}, NINF <= α^2 <= 1).
686
+ @kwarg kp2: Complementary modulus squared (C{float}, k'^2 >= 0).
687
+ @kwarg alphap2: Complementary parameter squared (C{float}, α'^2 >= 0).
688
+
689
+ @raise EllipticError: Invalid B{C{k2}}, B{C{alpha2}}, B{C{kp2}}
690
+ or B{C{alphap2}}.
691
+
692
+ @note: The arguments must satisfy C{B{k2} + B{kp2} = 1} and
693
+ C{B{alpha2} + B{alphap2} = 1}. No checking is done
694
+ that these conditions are met to enable accuracy to be
695
+ maintained, e.g., when C{k} is very close to unity.
696
+ '''
697
+ if self.__dict__:
698
+ _update_all(self, _Named.iteration._uname, Base=Property_RO)
699
+
700
+ self._k2 = Scalar_(k2=k2, Error=EllipticError, low=None, high=_1_0)
701
+ self._kp2 = Scalar_(kp2=((_1_0 - k2) if kp2 is None else kp2), Error=EllipticError)
702
+
703
+ self._alpha2 = Scalar_(alpha2=alpha2, Error=EllipticError, low=None, high=_1_0)
704
+ self._alphap2 = Scalar_(alphap2=((_1_0 - alpha2) if alphap2 is None else alphap2),
705
+ Error=EllipticError)
706
+
707
+ # Values of complete elliptic integrals for k = 0,1 and alpha = 0,1
708
+ # K E D
709
+ # k = 0: pi/2 pi/2 pi/4
710
+ # k = 1: inf 1 inf
711
+ # Pi G H
712
+ # k = 0, alpha = 0: pi/2 pi/2 pi/4
713
+ # k = 1, alpha = 0: inf 1 1
714
+ # k = 0, alpha = 1: inf inf pi/2
715
+ # k = 1, alpha = 1: inf inf inf
716
+ #
717
+ # G(0, k) = Pi(0, k) = H(1, k) = E(k)
718
+ # H(0, k) = K(k) - D(k)
719
+ # Pi(alpha2, 0) = G(alpha2, 0) = pi / (2 * sqrt(1 - alpha2))
720
+ # H( alpha2, 0) = pi / (2 * (sqrt(1 - alpha2) + 1))
721
+ # Pi(alpha2, 1) = inf
722
+ # G( alpha2, 1) = H(alpha2, 1) = RC(1, alphap2)
723
+
724
+ def sncndn(self, x):
725
+ '''The Jacobi elliptic function.
726
+
727
+ @arg x: The argument (C{float}).
728
+
729
+ @return: An L{Elliptic3Tuple}C{(sn, cn, dn)} with
730
+ C{*n(B{x}, k)}.
731
+
732
+ @raise EllipticError: No convergence.
733
+ '''
734
+ self._iteration = 0 # reset
735
+ try: # Bulirsch's sncndn routine, p 89.
736
+ if self.kp2:
737
+ c, d, cd, mn = self._sncndn4
738
+ dn = _1_0
739
+ sn, cn = _sincos2(x * cd)
740
+ if sn:
741
+ a = cn / sn
742
+ c *= a
743
+ for m, n in reversed(mn):
744
+ a *= c
745
+ c *= dn
746
+ dn = (n + a) / (m + a)
747
+ a = c / m
748
+ a = _1_0 / hypot1(c)
749
+ sn = neg(a) if _signBit(sn) else a
750
+ cn = c * sn
751
+ if d and _signBit(self.kp2):
752
+ cn, dn = dn, cn
753
+ sn = sn / d # /= chokes PyChecker
754
+ else:
755
+ sn = tanh(x)
756
+ cn = dn = _1_0 / cosh(x)
757
+
758
+ except Exception as e:
759
+ raise _ellipticError(self.sncndn, x, kp2=self.kp2, cause=e)
760
+
761
+ return Elliptic3Tuple(sn, cn, dn, iteration=self._iteration)
762
+
763
+ def _sncndn3(self, phi):
764
+ '''(INTERNAL) Helper for C{.fEinv} and C{._fXf}.
765
+ '''
766
+ sn, cn = _sincos2(phi)
767
+ return sn, cn, self.fDelta(sn, cn)
768
+
769
+ @Property_RO
770
+ def _sncndn4(self):
771
+ '''(INTERNAL) Get Bulirsch' 4-tuple C{(c, d, cd, mn)}.
772
+ '''
773
+ # Bulirsch's sncndn routine, p 89.
774
+ d, mc = 0, self.kp2
775
+ if _signBit(mc):
776
+ d = _1_0 - mc
777
+ mc = neg(mc / d)
778
+ d = sqrt(d)
779
+
780
+ mn, a = [], _1_0
781
+ for i in range(1, _TRIPS): # GEOGRAPHICLIB_PANIC
782
+ mc = sqrt(mc)
783
+ mn.append((a, mc))
784
+ c = (a + mc) * _0_5
785
+ r = fabs(mc - a)
786
+ t = _TolJAC * a
787
+ if r <= t: # 6 trips, quadratic
788
+ _iterations(self, i)
789
+ break
790
+ mc *= a
791
+ a = c
792
+ else: # PYCHOK no cover
793
+ raise _convergenceError(r, t)
794
+ cd = (c * d) if d else c
795
+ return c, d, cd, mn
796
+
797
+ @staticmethod
798
+ def fRC(x, y):
799
+ '''Degenerate symmetric integral of the first kind C{RC(x, y)}.
800
+
801
+ @return: C{RC(x, y)}, equivalent to C{RF(x, y, y)}.
802
+
803
+ @see: U{C{RC} definition<https://DLMF.NIST.gov/19.2.E17>} and
804
+ U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
805
+ '''
806
+ return _rC(None, x, y)
807
+
808
+ @staticmethod
809
+ def fRD(x, y, z, *over):
810
+ '''Degenerate symmetric integral of the third kind C{RD(x, y, z)}.
811
+
812
+ @return: C{RD(x, y, z) / over}, equivalent to C{RJ(x, y, z, z)
813
+ / over} with C{over} typically 3.
814
+
815
+ @see: U{C{RD} definition<https://DLMF.NIST.gov/19.16.E5>} and
816
+ U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
817
+ '''
818
+ try:
819
+ return float(_RD(None, x, y, z, *over))
820
+ except Exception as e:
821
+ raise _ellipticError(Elliptic.fRD, x, y, z, *over, cause=e)
822
+
823
+ @staticmethod
824
+ def fRF(x, y, z=0):
825
+ '''Symmetric or complete symmetric integral of the first kind
826
+ C{RF(x, y, z)} respectively C{RF(x, y)}.
827
+
828
+ @return: C{RF(x, y, z)} or C{RF(x, y)} for missing or zero B{C{z}}.
829
+
830
+ @see: U{C{RF} definition<https://DLMF.NIST.gov/19.16.E1>} and
831
+ U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
832
+ '''
833
+ try:
834
+ return float(_RF3(None, x, y, z)) if z else _rF2(None, x, y)
835
+ except Exception as e:
836
+ raise _ellipticError(Elliptic.fRF, x, y, z, cause=e)
837
+
838
+ @staticmethod
839
+ def fRG(x, y, z=0):
840
+ '''Symmetric or complete symmetric integral of the second kind
841
+ C{RG(x, y, z)} respectively C{RG(x, y)}.
842
+
843
+ @return: C{RG(x, y, z)} or C{RG(x, y)} for missing or zero B{C{z}}.
844
+
845
+ @see: U{C{RG} definition<https://DLMF.NIST.gov/19.16.E3>},
846
+ U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>} and
847
+ U{RG<https://GeographicLib.SourceForge.io/C++/doc/
848
+ EllipticFunction_8cpp_source.html#l00096>} version 2.3.
849
+ '''
850
+ try:
851
+ return _rG2(None, x, y) if z == 0 else (
852
+ _rG2(None, z, x) if y == 0 else (
853
+ _rG2(None, y, z) if x == 0 else _rG3(None, x, y, z)))
854
+ except Exception as e:
855
+ t = _negative_ if min(x, y, z) < 0 else NN
856
+ raise _ellipticError(Elliptic.fRG, x, y, z, cause=e, txt=t)
857
+
858
+ @staticmethod
859
+ def fRJ(x, y, z, p):
860
+ '''Symmetric integral of the third kind C{RJ(x, y, z, p)}.
861
+
862
+ @return: C{RJ(x, y, z, p)}.
863
+
864
+ @see: U{C{RJ} definition<https://DLMF.NIST.gov/19.16.E2>} and
865
+ U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
866
+ '''
867
+ try:
868
+ return float(_RJ(None, x, y, z, p))
869
+ except Exception as e:
870
+ raise _ellipticError(Elliptic.fRJ, x, y, z, p, cause=e)
871
+
872
+ @staticmethod
873
+ def _RFRD(x, y, z, m):
874
+ # in .auxilats.AuxDLat.DE, .auxilats.AuxLat.Rectifying
875
+ try: # float(RF(x, y, z) - RD(x, y, z, 3 / m))
876
+ R = _RF3(None, x, y, z)
877
+ if m:
878
+ R -= _RD(None, x, y, z, _3_0 / m)
879
+ except Exception as e:
880
+ raise _ellipticError(Elliptic._RFRD, x, y, z, m, cause=e)
881
+ return float(R)
882
+
883
+ _allPropertiesOf_n(15, Elliptic) # # PYCHOK assert, see Elliptic.reset
884
+
885
+
886
+ class EllipticError(_ValueError):
887
+ '''Elliptic function, integral, convergence or other L{Elliptic} issue.
888
+ '''
889
+ pass
890
+
891
+
892
+ class Elliptic3Tuple(_NamedTuple):
893
+ '''3-Tuple C{(sn, cn, dn)} all C{scalar}.
894
+ '''
895
+ _Names_ = ('sn', 'cn', 'dn')
896
+ _Units_ = ( Scalar, Scalar, Scalar)
897
+
898
+
899
+ class _L(list):
900
+ '''(INTERNAL) Helper for C{_RD}, C{_RF3} and C{_RJ}.
901
+ '''
902
+ _a0 = None
903
+ # _xyzp = ()
904
+
905
+ def __init__(self, *xyzp): # x, y, z [, p]
906
+ list.__init__(self, xyzp)
907
+ self._xyzp = xyzp
908
+
909
+ def a0(self, n):
910
+ '''Compute the initial C{a}.
911
+ '''
912
+ t = tuple(self)
913
+ m = n - len(t)
914
+ if m > 0:
915
+ t += t[-1:] * m
916
+ try:
917
+ a = Fsum(*t).fover(n)
918
+ except ValueError: # Fsum(NAN) exception
919
+ a = _sum(t) / n
920
+ self._a0 = a
921
+ return a
922
+
923
+ def amrs4(self, inst, y, Tol):
924
+ '''Yield Carlson 4-tuples C{(An, mul, lam, s)} plus sentinel, with
925
+ C{lam = fdot(sqrt(x), ... (z))} and C{s = (sqrt(x), ... (p))}.
926
+ '''
927
+ L = self
928
+ a = L.a0(5 if y else 3)
929
+ m = 1
930
+ t = max(fabs(a - _) for _ in L) / Tol
931
+ for i in range(_TRIPS):
932
+ d = fabs(a * m)
933
+ if d > t: # 3-6 trips
934
+ _iterations(inst, i)
935
+ break
936
+ s = map2(sqrt, L) # sqrt(x), srqt(y), sqrt(z) [, sqrt(p)]
937
+ try:
938
+ r = fdot(s[:3], s[1], s[2], s[0]) # sqrt(x) * sqrt(y) + ...
939
+ except ValueError: # Fsum(NAN) exception
940
+ r = _sum(s[i] * s[(i + 1) % 3] for i in range(3))
941
+ L[:] = [(r + _) * _0_25 for _ in L]
942
+ a = (r + a) * _0_25
943
+ if y: # yield only if used
944
+ yield a, m, r, s # L[2] is next z
945
+ m *= 4
946
+ else: # PYCHOK no cover
947
+ raise _convergenceError(d, t, thresh=True)
948
+ yield a, m, None, () # sentinel: same a, next m, no r and s
949
+
950
+ def rescale(self, am, *xs):
951
+ '''Rescale C{x}, C{y}, ...
952
+ '''
953
+ # assert am
954
+ a0 = self._a0
955
+ for x in xs:
956
+ yield (a0 - x) / am
957
+
958
+
959
+ def _ab2(inst, x, y):
960
+ '''(INTERNAL) Yield Carlson 2-tuples C{(xn, yn)}.
961
+ '''
962
+ a, b = sqrt(x), sqrt(y)
963
+ if b > a:
964
+ a, b = b, a
965
+ yield a, b # initial x0, y0
966
+ for i in range(_TRIPS):
967
+ d = fabs(a - b)
968
+ t = _TolRG0 * a
969
+ if d <= t: # 3-4 trips
970
+ _iterations(inst, i)
971
+ break
972
+ a, b = ((a + b) * _0_5), sqrt(a * b)
973
+ yield a, b # xn, yn
974
+ else: # PYCHOK no cover
975
+ raise _convergenceError(d, t)
976
+
977
+
978
+ def _convergenceError(d, tol, **thresh):
979
+ '''(INTERNAL) Format a no-convergence Error.
980
+ '''
981
+ t = Fmt.no_convergence(d, tol, **thresh)
982
+ return ValueError(t) # txt only
983
+
984
+
985
+ def _deltaX(sn, cn, dn, cX, fX):
986
+ '''(INTERNAL) Helper for C{Elliptic.deltaD} thru C{.deltaPi}.
987
+ '''
988
+ try:
989
+ if cn is None or dn is None:
990
+ raise ValueError(_invalid_)
991
+
992
+ if _signBit(cn):
993
+ sn, cn = neg_(sn, cn)
994
+ r = fX(sn, cn, dn) * PI_2 / cX
995
+ return r - atan2(sn, cn)
996
+
997
+ except Exception as e:
998
+ n = NN(_delta_, fX.__name__[1:])
999
+ raise _ellipticError(n, sn, cn, dn, cause=e)
1000
+
1001
+
1002
+ def _ellipticError(where, *args, **kwds_cause_txt):
1003
+ '''(INTERNAL) Format an L{EllipticError}.
1004
+ '''
1005
+ def _x_t_kwds(cause=None, txt=NN, **kwds):
1006
+ return cause, txt, kwds
1007
+
1008
+ x, t, kwds = _x_t_kwds(**kwds_cause_txt)
1009
+
1010
+ n = _dunder_nameof(where, where)
1011
+ n = _DOT_(Elliptic.__name__, n)
1012
+ n = _SPACE_(_invokation_, n)
1013
+ u = unstr(n, *args, **kwds)
1014
+ return EllipticError(u, cause=x, txt=t)
1015
+
1016
+
1017
+ def _Horner(S, e1, E2, E3, E4, E5, *over):
1018
+ '''(INTERNAL) Horner form for C{_RD} and C{_RJ} below.
1019
+ '''
1020
+ E22 = E2**2
1021
+ # Polynomial is <https://DLMF.NIST.gov/19.36.E2>
1022
+ # (1 - 3*E2/14 + E3/6 + 9*E2**2/88 - 3*E4/22 - 9*E2*E3/52
1023
+ # + 3*E5/26 - E2**3/16 + 3*E3**2/40 + 3*E2*E4/20
1024
+ # + 45*E2**2*E3/272 - 9*(E3*E4+E2*E5)/68)
1025
+ # converted to Horner-like form ...
1026
+ F = Fsum
1027
+ e = e1 * 4084080
1028
+ S *= e
1029
+ S += F(E2 * -540540, 471240).fmul(E5)
1030
+ S += F(E2 * 612612, E3 * -540540, -556920).fmul(E4)
1031
+ S += F(E2 * -706860, E22 * 675675, E3 * 306306, 680680).fmul(E3)
1032
+ S += F(E2 * 417690, E22 * -255255, -875160).fmul(E2)
1033
+ S += 4084080
1034
+ return S.fdiv((over[0] * e) if over else e) # Fsum
1035
+
1036
+
1037
+ def _iterations(inst, i):
1038
+ '''(INTERNAL) Aggregate iterations B{C{i}}.
1039
+ '''
1040
+ if inst and i > 0:
1041
+ inst._iteration += i
1042
+
1043
+
1044
+ def _3over(a, b):
1045
+ '''(INTERNAL) Return C{3 / (a * b)}.
1046
+ '''
1047
+ return _over(_3_0, a * b)
1048
+
1049
+
1050
+ def _rC(unused, x, y):
1051
+ '''(INTERNAL) Defined only for C{y != 0} and C{x >= 0}.
1052
+ '''
1053
+ d = x - y
1054
+ if d < 0: # catch NaN
1055
+ # <https://DLMF.NIST.gov/19.2.E18>
1056
+ d = -d
1057
+ r = atan(sqrt(d / x)) if x > 0 else PI_2
1058
+ elif d == 0: # XXX d < EPS0? or EPS02 or _EPSmin
1059
+ d, r = y, _1_0
1060
+ elif y > 0: # <https://DLMF.NIST.gov/19.2.E19>
1061
+ r = asinh(sqrt(d / y)) # atanh(sqrt((x - y) / x))
1062
+ elif y < 0: # <https://DLMF.NIST.gov/19.2.E20>
1063
+ r = asinh(sqrt(-x / y)) # atanh(sqrt(x / (x - y)))
1064
+ else: # PYCHOK no cover
1065
+ raise _ellipticError(Elliptic.fRC, x, y)
1066
+ return r / sqrt(d) # float
1067
+
1068
+
1069
+ def _RD(inst, x, y, z, *over):
1070
+ '''(INTERNAL) Carlson, eqs 2.28 - 2.34.
1071
+ '''
1072
+ L = _L(x, y, z)
1073
+ S = _D()
1074
+ for a, m, r, s in L.amrs4(inst, True, _TolRF):
1075
+ if s:
1076
+ S += _over(_3_0, (r + z) * s[2] * m)
1077
+ z = L[2] # s[2] = sqrt(z)
1078
+ x, y = L.rescale(-a * m, x, y)
1079
+ xy = x * y
1080
+ z = (x + y) / _3_0
1081
+ z2 = z**2
1082
+ return _Horner(S(_1_0), sqrt(a) * a * m,
1083
+ xy - _6_0 * z2,
1084
+ (xy * _3_0 - _8_0 * z2) * z,
1085
+ (xy - z2) * _3_0 * z2,
1086
+ xy * z2 * z, *over) # Fsum
1087
+
1088
+
1089
+ def _rF2(inst, x, y): # 2-arg version, z=0
1090
+ '''(INTERNAL) Carlson, eqs 2.36 - 2.38.
1091
+ '''
1092
+ for a, b in _ab2(inst, x, y): # PYCHOK yield
1093
+ pass
1094
+ return _over(PI, a + b) # float
1095
+
1096
+
1097
+ def _RF3(inst, x, y, z): # 3-arg version
1098
+ '''(INTERNAL) Carlson, eqs 2.2 - 2.7.
1099
+ '''
1100
+ L = _L(x, y, z)
1101
+ for a, m, _, _ in L.amrs4(inst, False, _TolRF):
1102
+ pass
1103
+ x, y = L.rescale(a * m, x, y)
1104
+ z = neg(x + y)
1105
+ xy = x * y
1106
+ e2 = xy - z**2
1107
+ e3 = xy * z
1108
+ e4 = e2**2
1109
+ # Polynomial is <https://DLMF.NIST.gov/19.36.E1>
1110
+ # (1 - E2/10 + E3/14 + E2**2/24 - 3*E2*E3/44
1111
+ # - 5*E2**3/208 + 3*E3**2/104 + E2**2*E3/16)
1112
+ # converted to Horner-like form ...
1113
+ S = Fsum(e4 * 15015, e3 * 6930, e2 * -16380, 17160).fmul(e3)
1114
+ S += Fsum(e4 * -5775, e2 * 10010, -24024).fmul(e2)
1115
+ S += 240240
1116
+ return S.fdiv(sqrt(a) * 240240) # Fsum
1117
+
1118
+
1119
+ def _rG2(inst, x, y, PI_=PI_4): # 2-args
1120
+ '''(INTERNAL) Carlson, eqs 2.36 - 2.39.
1121
+ '''
1122
+ m = -1 # neg!
1123
+ S = _D()
1124
+ # assert not S
1125
+ for a, b in _ab2(inst, x, y): # PYCHOK yield
1126
+ if S:
1127
+ S += (a - b)**2 * m
1128
+ m *= 2
1129
+ else: # initial
1130
+ S += (a + b)**2 * _0_5
1131
+ return S(PI_).fover(a + b)
1132
+
1133
+
1134
+ def _rG3(inst, x, y, z): # 3-arg version
1135
+ '''(INTERNAL) C{x}, C{y} and C{z} all non-zero, see C{.fRG}.
1136
+ '''
1137
+ R = _RF3(inst, x, y, z) * z
1138
+ rd = (x - z) * (z - y) # - (y - z)
1139
+ if rd: # Carlson, eq 1.7
1140
+ R += _RD(inst, x, y, z, _3_0 / rd)
1141
+ R += sqrt(x * y / z)
1142
+ return R.fover(_2_0)
1143
+
1144
+
1145
+ def _RJ(inst, x, y, z, p, *over):
1146
+ '''(INTERNAL) Carlson, eqs 2.17 - 2.25.
1147
+ '''
1148
+ def _xyzp(x, y, z, p):
1149
+ return (x + p) * (y + p) * (z + p)
1150
+
1151
+ L = _L(x, y, z, p)
1152
+ n = neg(_xyzp(x, y, z, -p))
1153
+ S = _D()
1154
+ for a, m, _, s in L.amrs4(inst, True, _TolRD):
1155
+ if s:
1156
+ d = _xyzp(*s)
1157
+ if d:
1158
+ if n:
1159
+ rc = _rC(inst, _1_0, n / d**2 + _1_0)
1160
+ n *= _1_64th # /= chokes PyChecker
1161
+ else:
1162
+ rc = _1_0 # == _rC(None, _1_0, _1_0)
1163
+ S += rc / (d * m)
1164
+ else: # PYCHOK no cover
1165
+ return NAN
1166
+ x, y, z = L.rescale(a * m, x, y, z)
1167
+ p = Fsum(x, y, z).fover(_N_2_0)
1168
+ p2 = p**2
1169
+ p3 = p2 * p
1170
+ E2 = Fsum(x * y, x * z, y * z, -p2 * _3_0)
1171
+ E2p = E2 * p
1172
+ xyz = x * y * z
1173
+ return _Horner(S(_6_0), sqrt(a) * a * m, E2,
1174
+ Fsum(p3 * _4_0, xyz, E2p * _2_0),
1175
+ Fsum(p3 * _3_0, E2p, xyz * _2_0).fmul(p),
1176
+ xyz * p2, *over) # Fsum
1177
+
1178
+ # **) MIT License
1179
+ #
1180
+ # Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved.
1181
+ #
1182
+ # Permission is hereby granted, free of charge, to any person obtaining a
1183
+ # copy of this software and associated documentation files (the "Software"),
1184
+ # to deal in the Software without restriction, including without limitation
1185
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
1186
+ # and/or sell copies of the Software, and to permit persons to whom the
1187
+ # Software is furnished to do so, subject to the following conditions:
1188
+ #
1189
+ # The above copyright notice and this permission notice shall be included
1190
+ # in all copies or substantial portions of the Software.
1191
+ #
1192
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1193
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1194
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1195
+ # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
1196
+ # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1197
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1198
+ # OTHER DEALINGS IN THE SOFTWARE.