pygeodesy 25.5.25__py2.py3-none-any.whl → 25.7.25__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.
pygeodesy/elliptic.py CHANGED
@@ -76,17 +76,18 @@ U{22<https://DLMF.NIST.gov/22>}.
76
76
  from __future__ import division as _; del _ # noqa: E702 ;
77
77
 
78
78
  from pygeodesy.basics import copysign0, map2, neg, neg_, typename
79
- from pygeodesy.constants import EPS, INF, NAN, PI, PI_2, PI_4, _0_0, \
80
- _0_25, _0_5, _1_0, _2_0, _N_2_0, _3_0, \
81
- _4_0, _6_0, _8_0, _64_0, _180_0, _360_0, \
82
- _EPStol as _TolJAC, _over, \
83
- _EPSjam as _TolJAM # PYCHOK used!
84
- # from pygeodesy.errors import _ValueError # from .fmath
85
- from pygeodesy.fmath import favg, hypot1, zqrt, _ValueError
86
- from pygeodesy.fsums import Fsum, _sum
79
+ from pygeodesy.constants import EPS, INF, NAN, PI, PI_2, PI_4, \
80
+ _EPStol as _TolJAC, _0_0, _0_25, \
81
+ _0_5, _1_0, _2_0, _N_2_0, _3_0, \
82
+ _4_0, _6_0, _8_0, _64_0, _180_0, \
83
+ _360_0, _over
84
+ from pygeodesy.constants import _EPSjam as _TolJAM # PYCHOK used!
85
+ # from pygeodesy.errors import _ValueError # from .fsums
86
+ from pygeodesy.fmath import favg, Fdot_, fma, hypot1, zqrt
87
+ from pygeodesy.fsums import Fsum, _fsum, _ValueError
87
88
  # from pygeodesy.internals import typename # from .basics
88
- from pygeodesy.interns import NN, _delta_, _DOT_, _f_, _invalid_, _invokation_, \
89
- _negative_, _SPACE_
89
+ from pygeodesy.interns import NN, _delta_, _DOT_, _f_, _invalid_, \
90
+ _invokation_, _negative_, _SPACE_
90
91
  from pygeodesy.karney import _K_2_0, _norm180, _signBit, _sincos2
91
92
  # from pygeodesy.lazily import _ALL_LAZY # from .named
92
93
  from pygeodesy.named import _Named, _NamedTuple, _ALL_LAZY, Fmt, unstr
@@ -99,48 +100,23 @@ from math import asin, asinh, atan, ceil, cosh, fabs, floor, radians, \
99
100
  sin, sinh, sqrt, tan, tanh # tan as _tan
100
101
 
101
102
  __all__ = _ALL_LAZY.elliptic
102
- __version__ = '25.05.12'
103
+ __version__ = '25.06.02'
103
104
 
104
105
  _TolRD = zqrt(EPS * 0.002)
105
106
  _TolRF = zqrt(EPS * 0.030)
106
107
  _TolRG0 = _TolJAC * 2.7
107
- _TRIPS = 25 # Max depth, 6-7 might be sufficient
108
+ _TRIPS = 28 # Max depth, 6-18 might be sufficient
108
109
 
109
110
 
110
111
  class _Cs(object):
111
112
  '''(INTERAL) Complete integrals cache.
112
113
  '''
113
114
  def __init__(self, **kwds):
115
+ # for n,v in kwds.items():
116
+ # setattr(self, n, v)
114
117
  self.__dict__ = kwds
115
118
 
116
119
 
117
- class _Dsum(list):
118
- '''(INTERNAL) Deferred C{Fsum}.
119
- '''
120
- def __call__(self, s):
121
- try: # Fsum *= s
122
- return Fsum(*self).fmul(s)
123
- except ValueError: # Fsum(NAN) exception
124
- return _sum(self) * s
125
-
126
- def __iadd__(self, x):
127
- list.append(self, x)
128
- return self
129
-
130
-
131
- class _Dadd(_Dsum):
132
- '''(INTERNAL) Deferred C{Fsum} for C{_List.amrs4}.
133
- '''
134
- def __init__(self, mul):
135
- self._mul = mul
136
-
137
- def __add__(self, x):
138
- self += x
139
- r = self(self._mul)
140
- _ = self.pop()
141
- return r # Fsum or float
142
-
143
-
144
120
  class Elliptic(_Named):
145
121
  '''Elliptic integrals and functions.
146
122
 
@@ -165,9 +141,9 @@ class Elliptic(_Named):
165
141
  that case, we have C{Π(φ, 0, k) = F(φ, k), G(φ, 0, k) =
166
142
  E(φ, k)} and C{H(φ, 0, k) = F(φ, k) - D(φ, k)}.
167
143
  '''
168
- self.reset(k2=k2, alpha2=alpha2, kp2=kp2, alphap2=alphap2)
169
144
  if name:
170
145
  self.name = name
146
+ self._reset(k2, alpha2, kp2, alphap2)
171
147
 
172
148
  @Property_RO
173
149
  def alpha2(self):
@@ -181,6 +157,32 @@ class Elliptic(_Named):
181
157
  '''
182
158
  return self._alphap2
183
159
 
160
+ @Property_RO
161
+ def _b4(self):
162
+ '''(INTERNAL) Get Bulirsch' 4-tuple C{(c, d, cd, mn)}.
163
+ '''
164
+ d, b = 0, self.kp2 # note, kp2 >= 0 always here
165
+ if _signBit(b): # PYCHOK no cover
166
+ d = _1_0 - b
167
+ b = neg(b / d)
168
+ d = sqrt(d)
169
+ ab, a = [], _1_0
170
+ for i in range(1, _TRIPS): # GEOGRAPHICLIB_PANIC
171
+ b = sqrt(b)
172
+ ab.append((a, b))
173
+ c = favg(a, b)
174
+ r = fabs(a - b)
175
+ if r <= (a * _TolJAC): # 6 trips, quadratic
176
+ self._iteration += i
177
+ break
178
+ t = a
179
+ b *= a
180
+ a = c
181
+ else: # PYCHOK no cover
182
+ raise _convergenceError(r / t, _TolJAC)
183
+ cd = (c * d) if d else c
184
+ return c, d, cd, tuple(reversed(ab))
185
+
184
186
  @Property_RO
185
187
  def cD(self):
186
188
  '''Get Jahnke's complete integral C{D(k)} (C{float}),
@@ -190,28 +192,28 @@ class Elliptic(_Named):
190
192
 
191
193
  @Property_RO
192
194
  def _cDEKEeps(self):
193
- '''(INTERNAL) Get the complete integrals D, E, K and KE plus C{eps}.
195
+ '''(INTERNAL) Get the complete integrals D, E, K, KE and C{eps}.
194
196
  '''
195
197
  k2, kp2 = self.k2, self.kp2
196
198
  if k2:
197
199
  if kp2:
198
200
  try:
199
- self._iteration = 0
201
+ # self._iteration = 0
200
202
  # D(k) = (K(k) - E(k))/k2, Carlson eq.4.3
201
203
  # <https://DLMF.NIST.gov/19.25.E1>
202
- D = _RD(self, _0_0, kp2, _1_0, _3_0)
204
+ D = _RD(_0_0, kp2, _1_0, _3_0, self)
203
205
  cD = float(D)
204
206
  # Complete elliptic integral E(k), Carlson eq. 4.2
205
207
  # <https://DLMF.NIST.gov/19.25.E1>
206
- cE = _rG2(self, kp2, _1_0, PI_=PI_2)
208
+ cE = _rG2(kp2, _1_0, self, PI_=PI_2)
207
209
  # Complete elliptic integral K(k), Carlson eq. 4.1
208
210
  # <https://DLMF.NIST.gov/19.25.E1>
209
- cK = _rF2(self, kp2, _1_0)
211
+ cK = _rF2(kp2, _1_0, self)
210
212
  cKE = float(D.fmul(k2))
211
213
  eps = k2 / (sqrt(kp2) + _1_0)**2
212
214
 
213
- except Exception as e:
214
- raise _ellipticError(self.reset, k2=k2, kp2=kp2, cause=e)
215
+ except Exception as X:
216
+ raise _ellipticError(self._cDEKEeps, k2=k2, kp2=kp2, cause=X)
215
217
  else:
216
218
  cD = cK = cKE = INF
217
219
  cE = _1_0
@@ -244,17 +246,17 @@ class Elliptic(_Named):
244
246
  '''
245
247
  alpha2, alphap2, kp2 = self.alpha2, self.alphap2, self.kp2
246
248
  try:
247
- self._iteration = 0
249
+ # self._iteration = 0
248
250
  if alpha2:
249
251
  if alphap2:
250
252
  if kp2: # <https://DLMF.NIST.gov/19.25.E2>
251
253
  cK = self.cK
252
- Rj = _RJ(self, _0_0, kp2, _1_0, alphap2, _3_0)
253
- cG = float(Rj * (alpha2 - self.k2) + cK) # G(alpha2, k)
254
- cH = -float(Rj * alphap2 - cK) # H(alpha2, k)
255
- cPi = float(Rj * alpha2 + cK) # Pi(alpha2, k)
254
+ Rj = _RJfma(_0_0, kp2, _1_0, alphap2, _3_0, self)
255
+ cG = Rj.ma(alpha2 - self.k2, cK) # G(alpha2, k)
256
+ cH = -Rj.ma(alphap2, -cK) # H(alpha2, k)
257
+ cPi = Rj.ma(alpha2, cK) # Pi(alpha2, k)
256
258
  else:
257
- cG = cH = _rC(self, _1_0, alphap2)
259
+ cG = cH = _rC(_1_0, alphap2)
258
260
  cPi = INF # XXX or NAN?
259
261
  else:
260
262
  cG = cH = cPi = INF # XXX or NAN?
@@ -272,11 +274,11 @@ class Elliptic(_Named):
272
274
  # RF(x, 1) - RD(0, x, 1) / 3 = x * RD(0, 1, x) / 3 for x > 0
273
275
  # For k2 = 1 and alpha2 = 0, we have
274
276
  # H = int(cos(phi),...) = 1
275
- cH = float(_RD(self, _0_0, _1_0, kp2, _3_0 / kp2)) if kp2 else _1_0
277
+ cH = float(_RD(_0_0, _1_0, kp2, _3_0 / kp2, self)) if kp2 else _1_0
276
278
 
277
- except Exception as e:
278
- raise _ellipticError(self.reset, kp2=kp2, alpha2 =alpha2,
279
- alphap2=alphap2, cause=e)
279
+ except Exception as X:
280
+ raise _ellipticError(self._cGHPi, kp2=kp2, alpha2 =alpha2,
281
+ alphap2=alphap2, cause=X)
280
282
  return _Cs(cG=cG, cH=cH, cPi=cPi)
281
283
 
282
284
  @Property_RO
@@ -349,8 +351,8 @@ class Elliptic(_Named):
349
351
  t = atan2(stau, ctau)
350
352
  return self._Einv(t * self.cE / PI_2) - t
351
353
 
352
- except Exception as e:
353
- raise _ellipticError(self.deltaEinv, stau, ctau, cause=e)
354
+ except Exception as X:
355
+ raise _ellipticError(self.deltaEinv, stau, ctau, cause=X)
354
356
 
355
357
  def deltaF(self, sn, cn, dn):
356
358
  '''The periodic incomplete integral of the first kind.
@@ -416,7 +418,7 @@ class Elliptic(_Named):
416
418
  Phi = Fsum(phi)
417
419
  # first order correction
418
420
  phi = Phi.fsum_(self.eps * sin(phi * _2_0) / _N_2_0)
419
- self._iteration = 0
421
+ # self._iteration = 0
420
422
  # For kp2 close to zero use asin(r / cE) or J. P. Boyd,
421
423
  # Applied Math. and Computation 218, 7005-7013 (2012)
422
424
  # <https://DOI.org/10.1016/j.amc.2011.12.021>
@@ -429,7 +431,7 @@ class Elliptic(_Named):
429
431
  else: # PYCHOK no cover
430
432
  d = _0_0 # XXX or continue?
431
433
  if fabs(d) < _TolJAC: # 3-4 trips
432
- _iterations(self, i)
434
+ self._iteration += i
433
435
  break
434
436
  else: # PYCHOK no cover
435
437
  raise _convergenceError(d, _TolJAC)
@@ -457,7 +459,7 @@ class Elliptic(_Named):
457
459
  def _fD(sn, cn, dn):
458
460
  r = fabs(sn)**3
459
461
  if r:
460
- r = float(_RD(self, cn**2, dn**2, _1_0, _3_0 / r))
462
+ r = float(_RD(cn**2, dn**2, _1_0, _3_0 / r, self))
461
463
  return r
462
464
 
463
465
  return self._fXf(phi_or_sn, cn, dn, self.cD,
@@ -477,8 +479,8 @@ class Elliptic(_Named):
477
479
  (_1_0 - sn**2 * k2) if k2 < 0 else self.kp2)
478
480
  return sqrt(s) if s else _0_0
479
481
 
480
- except Exception as e:
481
- raise _ellipticError(self.fDelta, sn, cn, k2=k2, cause=e)
482
+ except Exception as X:
483
+ raise _ellipticError(self.fDelta, sn, cn, k2=k2, cause=X)
482
484
 
483
485
  def fE(self, phi_or_sn, cn=None, dn=None):
484
486
  '''The incomplete integral of the second kind in terms of
@@ -500,22 +502,21 @@ class Elliptic(_Named):
500
502
  cn2, dn2 = cn**2, dn**2
501
503
  kp2, k2 = self.kp2, self.k2
502
504
  if k2 <= 0: # Carlson, eq. 4.6, <https://DLMF.NIST.gov/19.25.E9>
503
- Ei = _RF3(self, cn2, dn2, _1_0)
505
+ Ei = _RF3(cn2, dn2, _1_0, self)
504
506
  if k2:
505
- Ei -= _RD(self, cn2, dn2, _1_0, _3over(k2, sn**2))
507
+ Ei -= _RD(cn2, dn2, _1_0, _3over(k2, sn**2), self)
506
508
  elif kp2 >= 0: # k2 > 0, <https://DLMF.NIST.gov/19.25.E10>
507
509
  Ei = _over(k2 * fabs(cn), dn) # float
508
510
  if kp2:
509
- Ei += (_RD( self, cn2, _1_0, dn2, _3over(k2, sn**2)) +
510
- _RF3(self, cn2, dn2, _1_0)) * kp2
511
- else: # kp2 < 0, <https://DLMF.NIST.gov/19.25.E11>
512
- Ei = _over(dn, fabs(cn))
513
- Ei -= _RD(self, dn2, _1_0, cn2, _3over(kp2, sn**2))
511
+ Ei += (_RD( cn2, _1_0, dn2, _3over(k2, sn**2), self) +
512
+ _RF3(cn2, dn2, _1_0, self)) * kp2
513
+ else: # PYCHOK no cover
514
+ Ei = _over(dn, fabs(cn)) # <https://DLMF.NIST.gov/19.25.E11>
515
+ Ei -= _RD(dn2, _1_0, cn2, _3over(kp2, sn**2), self)
514
516
  Ei *= fabs(sn)
515
- ei = float(Ei)
516
517
  else: # PYCHOK no cover
517
- ei = _0_0
518
- return ei
518
+ Ei = _0_0
519
+ return float(Ei)
519
520
 
520
521
  return self._fXf(phi_or_sn, cn, dn, self.cE,
521
522
  self.deltaE, _fE,
@@ -538,7 +539,8 @@ class Elliptic(_Named):
538
539
  else:
539
540
  e = ceil(deg / _360_0 - _0_5)
540
541
  deg -= e * _360_0
541
- return self.fE(radians(deg)) + e * self.cE * _4_0
542
+ e *= self.cE * _4_0
543
+ return self.fE(radians(deg)) + e
542
544
 
543
545
  def fEinv(self, x):
544
546
  '''The inverse of the incomplete integral of the second kind.
@@ -552,8 +554,8 @@ class Elliptic(_Named):
552
554
  '''
553
555
  try:
554
556
  return self._Einv(x)
555
- except Exception as e:
556
- raise _ellipticError(self.fEinv, x, cause=e)
557
+ except Exception as X:
558
+ raise _ellipticError(self.fEinv, x, cause=X)
557
559
 
558
560
  def fF(self, phi_or_sn, cn=None, dn=None):
559
561
  '''The incomplete integral of the first kind in terms of
@@ -571,7 +573,7 @@ class Elliptic(_Named):
571
573
  def _fF(sn, cn, dn):
572
574
  r = fabs(sn)
573
575
  if r:
574
- r = float(_RF3(self, cn**2, dn**2, _1_0).fmul(r))
576
+ r = float(_RF3(cn**2, dn**2, _1_0, self).fmul(r))
575
577
  return r
576
578
 
577
579
  return self._fXf(phi_or_sn, cn, dn, self.cK,
@@ -650,23 +652,22 @@ class Elliptic(_Named):
650
652
  def _fX(sn, cn, dn):
651
653
  if sn:
652
654
  cn2, dn2 = cn**2, dn**2
653
- R = _RF3(self, cn2, dn2, _1_0)
655
+ R = _RF3(cn2, dn2, _1_0, self)
654
656
  if aX:
655
657
  sn2 = sn**2
656
658
  p = sn2 * self.alphap2 + cn2
657
- R += _RJ(self, cn2, dn2, _1_0, p, _3over(aX, sn2))
659
+ R += _RJ(cn2, dn2, _1_0, p, _3over(aX, sn2), self)
658
660
  R *= fabs(sn)
659
- r = float(R)
660
661
  else: # PYCHOK no cover
661
- r = _0_0
662
- return r
662
+ R = _0_0
663
+ return float(R)
663
664
 
664
665
  return self._fXf(phi_or_sn, cn, dn, cX, deltaX, _fX)
665
666
 
666
667
  def _fXf(self, phi_or_sn, cn, dn, cX, deltaX, fX, k2_0=False, kp2_0=False):
667
668
  '''(INTERNAL) Helper for C{.fD}, C{.fE}, C{.fF} and C{._fXa}.
668
669
  '''
669
- self._iteration = 0 # aggregate
670
+ # self._iteration = 0 # aggregate
670
671
  phi = sn = phi_or_sn
671
672
  if cn is dn is None: # fX(phi) call
672
673
  if k2_0: # C++ version 2.4
@@ -712,7 +713,7 @@ class Elliptic(_Named):
712
713
  '''(INTERNAL) Get Jacobi amplitude 2-tuple C{(r, ac)}.
713
714
  '''
714
715
  a = r = _1_0
715
- b, c = self.kp2, self.k2
716
+ b, c = self.kp2, self.k2
716
717
  # assert b and c
717
718
  if c < 0: # Sala Eq. 5.8
718
719
  r = sqrt(b)
@@ -724,12 +725,12 @@ class Elliptic(_Named):
724
725
  c = favg(a, -b)
725
726
  a = favg(a, b) # == PI_2 / K
726
727
  ac.append((a, c))
727
- if c <= (a * _TolJAM): # 7 trips, quadratic
728
- _iterations(self, i)
728
+ if c <= (a * _TolJAM): # 7-18 trips, quadratic
729
+ self._iteration += i
729
730
  break
730
731
  else: # PYCHOK no cover
731
732
  raise _convergenceError(c / a, _TolJAM)
732
- r *= a * float(1 << i) # 2**i == 2**len(ac)
733
+ r *= a * pow(2, i) # 2**len(ac)
733
734
  return r, tuple(reversed(ac))
734
735
 
735
736
  @Property_RO
@@ -760,15 +761,23 @@ class Elliptic(_Named):
760
761
  that these conditions are met to enable accuracy to be
761
762
  maintained, e.g., when C{k} is very close to unity.
762
763
  '''
763
- if self.__dict__:
764
- _update_all(self, _Named.iteration._uname, Base=Property_RO)
764
+ _update_all(self, Base=Property_RO, needed=4)
765
+ self._reset(k2, alpha2, kp2, alphap2)
766
+
767
+ def _reset(self, k2, alpha2, kp2, alphap2):
768
+ '''(INITERNAL) Reset this elliptic.
769
+ '''
770
+ def _1p2(kp2, k2):
771
+ return (_1_0 - k2) if kp2 is None else kp2
772
+
773
+ def _S(**kwds):
774
+ return Scalar_(Error=EllipticError, **kwds)
765
775
 
766
- self._k2 = Scalar_(k2=k2, Error=EllipticError, low=None, high=_1_0)
767
- self._kp2 = Scalar_(kp2=((_1_0 - k2) if kp2 is None else kp2), Error=EllipticError)
776
+ self._k2 = _S(k2 = k2, low=None, high=_1_0)
777
+ self._kp2 = _S(kp2=_1p2(kp2, k2)) # low=_0_0
768
778
 
769
- self._alpha2 = Scalar_(alpha2=alpha2, Error=EllipticError, low=None, high=_1_0)
770
- self._alphap2 = Scalar_(alphap2=((_1_0 - alpha2) if alphap2 is None else alphap2),
771
- Error=EllipticError)
779
+ self._alpha2 = _S(alpha2 = alpha2, low=None, high=_1_0)
780
+ self._alphap2 = _S(alphap2=_1p2(alphap2, alpha2)) # low=_0_0
772
781
 
773
782
  # Values of complete elliptic integrals for k = 0,1 and alpha = 0,1
774
783
  # K E D
@@ -787,30 +796,31 @@ class Elliptic(_Named):
787
796
  # Pi(alpha2, 1) = inf
788
797
  # G( alpha2, 1) = H(alpha2, 1) = RC(1, alphap2)
789
798
 
799
+ self._iteration = 0
800
+
790
801
  def sncndn(self, x, jam=False):
791
802
  '''The Jacobi amplitude and elliptic function.
792
803
 
793
804
  @arg x: The argument (C{float}).
794
- @kwarg jam: If C{True}, use the Jacobi amplitude otherwise the
805
+ @kwarg jam: If C{True}, use the Jacobi amplitude otherwise
795
806
  Bulirsch' function (C{bool}).
796
807
 
797
808
  @return: An L{Elliptic3Tuple}C{(sn, cn, dn)} with C{*n(B{x}, k)}.
798
809
 
799
810
  @raise EllipticError: No convergence.
800
811
  '''
801
- self._iteration = 0 # reset
812
+ i = self._iteration
802
813
  try:
803
814
  if self.kp2:
804
- if jam: # Jacobi amplitude, C++ version 2.4
815
+ if jam: # Jacobi amplitude, C++ v 2.4
805
816
  sn, cn, dn = self._sncndn3(self._jam(x))
806
817
 
807
818
  else: # Bulirsch's sncndn routine, p 89 of
808
819
  # Numerische Mathematik 7, 78-90 (1965).
809
- # Implements DLMF Eqs 22.17.2 - 22.17.4,
810
- # but only good for .k2 > 1 or .kp2 < 0
811
- c, d, cd, mn = self._sncndn4
812
- dn = _1_0
820
+ # Implements DLMF Eqs 22.17.2 - 22.17.4
821
+ c, d, cd, mn = self._b4
813
822
  sn, cn = _sincos2(x * cd)
823
+ dn = _1_0
814
824
  if sn:
815
825
  a = cn / sn
816
826
  c *= a
@@ -829,10 +839,10 @@ class Elliptic(_Named):
829
839
  sn = tanh(x) # accurate for large abs(x)
830
840
  cn = dn = _1_0 / cosh(x)
831
841
 
832
- except Exception as e:
833
- raise _ellipticError(self.sncndn, x, kp2=self.kp2, cause=e)
842
+ except Exception as X:
843
+ raise _ellipticError(self.sncndn, x, kp2=self.kp2, cause=X)
834
844
 
835
- return Elliptic3Tuple(sn, cn, dn, iteration=self._iteration)
845
+ return Elliptic3Tuple(sn, cn, dn, iteration=self._iteration - i)
836
846
 
837
847
  def _sncndn3(self, phi):
838
848
  '''(INTERNAL) Helper for C{.fEinv}, C{._fXf} and C{.sncndn}.
@@ -840,32 +850,6 @@ class Elliptic(_Named):
840
850
  sn, cn = _sincos2(phi)
841
851
  return sn, cn, self.fDelta(sn, cn)
842
852
 
843
- @Property_RO
844
- def _sncndn4(self):
845
- '''(INTERNAL) Get Bulirsch' 4-tuple C{(c, d, cd, mn)}.
846
- '''
847
- d, b = 0, self.kp2
848
- if _signBit(b):
849
- d = _1_0 - b
850
- b = neg(b / d)
851
- d = sqrt(d)
852
- ab, a = [], _1_0
853
- for i in range(1, _TRIPS): # GEOGRAPHICLIB_PANIC
854
- b = sqrt(b)
855
- ab.append((a, b))
856
- c = favg(a, b)
857
- r = fabs(a - b)
858
- if r <= (a * _TolJAC): # 6 trips, quadratic
859
- _iterations(self, i)
860
- break
861
- t = a
862
- b *= a
863
- a = c
864
- else: # PYCHOK no cover
865
- raise _convergenceError(r / t, _TolJAC)
866
- cd = (c * d) if d else c
867
- return c, d, cd, tuple(reversed(ab))
868
-
869
853
  @staticmethod
870
854
  def fRC(x, y):
871
855
  '''Degenerate symmetric integral of the first kind C{RC(x, y)}.
@@ -875,7 +859,7 @@ class Elliptic(_Named):
875
859
  @see: U{C{RC} definition<https://DLMF.NIST.gov/19.2.E17>} and
876
860
  U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
877
861
  '''
878
- return _rC(None, x, y)
862
+ return _rC(x, y)
879
863
 
880
864
  @staticmethod
881
865
  def fRD(x, y, z, *over):
@@ -888,9 +872,9 @@ class Elliptic(_Named):
888
872
  U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
889
873
  '''
890
874
  try:
891
- return float(_RD(None, x, y, z, *over))
892
- except Exception as e:
893
- raise _ellipticError(Elliptic.fRD, x, y, z, *over, cause=e)
875
+ return float(_RD(x, y, z, *over))
876
+ except Exception as X:
877
+ raise _ellipticError(Elliptic.fRD, x, y, z, *over, cause=X)
894
878
 
895
879
  @staticmethod
896
880
  def fRF(x, y, z=0):
@@ -903,9 +887,9 @@ class Elliptic(_Named):
903
887
  U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
904
888
  '''
905
889
  try:
906
- return float(_RF3(None, x, y, z)) if z else _rF2(None, x, y)
907
- except Exception as e:
908
- raise _ellipticError(Elliptic.fRF, x, y, z, cause=e)
890
+ return float(_RF3(x, y, z)) if z else _rF2(x, y)
891
+ except Exception as X:
892
+ raise _ellipticError(Elliptic.fRF, x, y, z, cause=X)
909
893
 
910
894
  @staticmethod
911
895
  def fRG(x, y, z=0):
@@ -920,15 +904,15 @@ class Elliptic(_Named):
920
904
  EllipticFunction_8cpp_source.html#l00096>} version 2.3.
921
905
  '''
922
906
  try:
923
- return _rG2(None, x, y) if z == 0 else (
924
- _rG2(None, z, x) if y == 0 else (
925
- _rG2(None, y, z) if x == 0 else _rG3(None, x, y, z)))
926
- except Exception as e:
907
+ return _rG2(x, y) if z == 0 else (
908
+ _rG2(z, x) if y == 0 else (
909
+ _rG2(y, z) if x == 0 else _rG3(x, y, z)))
910
+ except Exception as X:
927
911
  t = _negative_ if min(x, y, z) < 0 else NN
928
- raise _ellipticError(Elliptic.fRG, x, y, z, cause=e, txt=t)
912
+ raise _ellipticError(Elliptic.fRG, x, y, z, cause=X, txt=t)
929
913
 
930
914
  @staticmethod
931
- def fRJ(x, y, z, p):
915
+ def fRJ(x, y, z, p): # *over
932
916
  '''Symmetric integral of the third kind C{RJ(x, y, z, p)}.
933
917
 
934
918
  @return: C{RJ(x, y, z, p)}.
@@ -937,19 +921,18 @@ class Elliptic(_Named):
937
921
  U{Carlson<https://ArXiv.org/pdf/math/9409227.pdf>}.
938
922
  '''
939
923
  try:
940
- return float(_RJ(None, x, y, z, p))
941
- except Exception as e:
942
- raise _ellipticError(Elliptic.fRJ, x, y, z, p, cause=e)
924
+ return float(_RJ(x, y, z, p))
925
+ except Exception as X:
926
+ raise _ellipticError(Elliptic.fRJ, x, y, z, p, cause=X)
943
927
 
944
928
  @staticmethod
945
- def _RFRD(x, y, z, m):
946
- # in .auxilats.AuxDLat.DE, .auxilats.AuxLat.Rectifying
929
+ def _RFRD(x, y, z, m): # in .auxilats.AuxDLat.DE, -.AuxLat.Rectifying
947
930
  try: # float(RF(x, y, z) - RD(x, y, z, 3 / m))
948
- R = _RF3(None, x, y, z)
931
+ R = _RF3(x, y, z)
949
932
  if m:
950
- R -= _RD(None, x, y, z, _3_0 / m)
951
- except Exception as e:
952
- raise _ellipticError(Elliptic._RFRD, x, y, z, m, cause=e)
933
+ R -= _RD(x, y, z, _3_0 / m)
934
+ except Exception as X:
935
+ raise _ellipticError(Elliptic._RFRD, x, y, z, m, cause=X)
953
936
  return float(R)
954
937
 
955
938
  _allPropertiesOf_n(16, Elliptic) # # PYCHOK assert, see Elliptic.reset
@@ -979,40 +962,38 @@ class _List(list):
979
962
  def a0(self, n):
980
963
  '''Compute the initial C{a}.
981
964
  '''
982
- A = _Dsum(self)
983
- while len(A) < n:
984
- A += A[-1]
985
- self._a0 = a = float(A(_1_0 / n))
986
- return a
987
-
988
- def amrs4(self, inst, y, Tol):
965
+ a = list(self)
966
+ m = n - len(a)
967
+ if m > 0:
968
+ a[-1] *= m + 1
969
+ self._a0 = a0 = _fsum(a) / n
970
+ return a0
971
+
972
+ def amrs4(self, y, Tol, inst=None):
989
973
  '''Yield Carlson 4-tuples C{(An, mul, lam, s)} plus sentinel, with
990
974
  C{lam = fdot(sqrt(x), ... (z))} and C{s = (sqrt(x), ... (p))}.
991
975
  '''
992
976
  L = self
993
977
  a = L.a0(5 if y else 3)
978
+ t = L.threshold(Tol)
994
979
  m = 1
995
- t = max(fabs(a - _) for _ in L) / Tol # thresh
996
980
  for i in range(_TRIPS):
997
981
  d = fabs(a * m)
998
982
  if d > t: # 3-6 trips
999
- _iterations(inst, i)
1000
983
  break
1001
- s = map2(sqrt, L) # sqrt(x), srqt(y), sqrt(z) [, sqrt(p)]
1002
- # Deferred fdot(s[:3], s[1], s[2], s[0]) + ...
1003
- Q = _Dadd(_0_25)
1004
- Q += s[0] * s[1]
1005
- Q += s[1] * s[2]
1006
- Q += s[2] * s[0]
1007
- L[:] = (float(Q + _) for _ in L)
1008
- a = float(Q + a)
984
+ s = map2(sqrt, L) # sqrt(x), sqrt(y), sqrt(z) [, sqrt(p)]
985
+ Q = _Qot3(*s) # (s[0] * s[1], s[1] * s[2], s[2] * s[0])
986
+ a = Q(a) # An = sum(An, *Q)) / 4
987
+ L[:] = map(Q, L) # x = sum(x, *Q) / 4, ...
1009
988
  if y: # yield only if used
1010
- r = _sum(Q) # fdot
989
+ r = float(Q) # lam = sum(Q)
1011
990
  yield a, m, r, s # L[2] is next z
1012
991
  m *= 4
1013
992
  else: # PYCHOK no cover
1014
993
  raise _convergenceError(d, t, thresh=True)
1015
994
  yield a, m, None, () # sentinel: same a, next m, no r and s
995
+ if inst:
996
+ inst._iteration += i
1016
997
 
1017
998
  def rescale(self, am, *xs):
1018
999
  '''Rescale C{x}, C{y}, ...
@@ -1023,24 +1004,63 @@ class _List(list):
1023
1004
  for x in xs:
1024
1005
  yield (a0 - x) * _am
1025
1006
 
1007
+ def threshold(self, Tol):
1008
+ '''Get the convergence C{threshold}.
1009
+ '''
1010
+ a0 = self._a0
1011
+ return max(fabs(x - a0) for x in self) / Tol
1012
+
1013
+
1014
+ # class _Qot3(Fsum):
1015
+ # '''(INTERNAL) "Quarter" 3-dot product.
1016
+ # '''
1017
+ # def __init__(self, x, y, z, *unused): # PYCHOK signature
1018
+ # Fsum.__init__(self, x * y, y * z, z * x)
1019
+ #
1020
+ # def __call__(self, a): # PYCHOK signature
1021
+ # return (self + a).fover(_4_0)
1026
1022
 
1027
- def _ab2(inst, x, y):
1028
- '''(INTERNAL) Yield Carlson 2-tuples C{(xn, yn)}.
1023
+
1024
+ class _Qot3(list):
1025
+ '''(INTERNAL) "Quarter" 3-dot product.
1026
+ '''
1027
+ def __init__(self, x, y, z, *unused): # PYCHOK signature
1028
+ try:
1029
+ D = Fdot_(x, y, y, z, z, x, f2product=True)
1030
+ except (OverflowError, TypeError, ValueError):
1031
+ D = Fsum(x * y, y * z, z * x, nonfinites=True)
1032
+ list.__init__(self, (0,) + D.partials) # NOT D.fsum2()!
1033
+
1034
+ def __call__(self, a):
1035
+ try:
1036
+ self[0] = a
1037
+ q = float(self) * _0_25
1038
+ finally:
1039
+ self[0] = 0
1040
+ return q
1041
+
1042
+ def __float__(self):
1043
+ return _fsum(self) # nonfinites=True
1044
+
1045
+
1046
+ def _ab3(x, y, inst=None):
1047
+ '''(INTERNAL) Yield Carlson 3-tuples C{(xn, yn, i)}.
1029
1048
  '''
1030
1049
  a, b = sqrt(x), sqrt(y)
1031
1050
  if b > a:
1032
1051
  b, a = a, b
1033
- for i in range(_TRIPS):
1034
- yield a, b # xi, yi
1052
+ for i in range(_TRIPS): # see
1053
+ yield a, b, i # xi, yi, i
1035
1054
  d = fabs(a - b)
1036
1055
  if d <= (a * _TolRG0): # 3-4 trips
1037
- _iterations(inst, i)
1038
1056
  break
1039
1057
  t = a
1040
1058
  a = favg(t, b)
1041
1059
  b = sqrt(t * b)
1042
1060
  else: # PYCHOK no cover
1043
1061
  raise _convergenceError(d / t, _TolRG0)
1062
+ if inst:
1063
+ inst._iteration += i
1044
1064
 
1045
1065
 
1046
1066
  def _convergenceError(d, tol, **thresh):
@@ -1062,9 +1082,9 @@ def _deltaX(sn, cn, dn, cX, fX):
1062
1082
  r = fX(sn, cn, dn) * PI_2 / cX
1063
1083
  return r - atan2(sn, cn)
1064
1084
 
1065
- except Exception as e:
1085
+ except Exception as X:
1066
1086
  n = NN(_delta_, typename(fX)[1:])
1067
- raise _ellipticError(n, sn, cn, dn, cause=e)
1087
+ raise _ellipticError(n, sn, cn, dn, cause=X)
1068
1088
 
1069
1089
 
1070
1090
  def _ellipticError(where, *args, **kwds_cause_txt):
@@ -1082,8 +1102,8 @@ def _ellipticError(where, *args, **kwds_cause_txt):
1082
1102
  return EllipticError(u, cause=x, txt=t)
1083
1103
 
1084
1104
 
1085
- def _Horner(S, e1, E2, E3, E4, E5, *over):
1086
- '''(INTERNAL) Horner form for C{_RD} and C{_RJ} below.
1105
+ def _Horner(S, e1, E2, E3, E4, E5, over):
1106
+ '''(INTERNAL) Horner-like form for C{_RD} and C{_RJ} below.
1087
1107
  '''
1088
1108
  E22 = E2**2
1089
1109
  # Polynomial is <https://DLMF.NIST.gov/19.36.E2>
@@ -1093,54 +1113,50 @@ def _Horner(S, e1, E2, E3, E4, E5, *over):
1093
1113
  # converted to Horner-like form ...
1094
1114
  e = e1 * 4084080
1095
1115
  S *= e
1096
- S += Fsum(E2 * -540540, 471240).fmul(E5)
1097
- S += Fsum(E2 * 612612, E3 * -540540, -556920).fmul(E4)
1098
- S += Fsum(E2 * -706860, E22 * 675675, E3 * 306306, 680680).fmul(E3)
1099
- S += Fsum(E2 * 417690, E22 * -255255, -875160).fmul(E2)
1116
+ S += Fsum(-E2 * 540540, 471240).fmul(E5)
1117
+ S += Fsum( E2 * 612612, -E3 * 540540, -556920).fmul(E4)
1118
+ S += Fsum(-E2 * 706860, E22 * 675675, E3 * 306306, 680680).fmul(E3)
1119
+ S += Fsum( E2 * 417690, -E22 * 255255, -875160).fmul(E2)
1100
1120
  S += 4084080
1101
- if over:
1102
- e *= over[0]
1121
+ if over != _1_0:
1122
+ e *= over
1103
1123
  return S.fdiv(e) # Fsum
1104
1124
 
1105
1125
 
1106
- def _iterations(inst, i):
1107
- '''(INTERNAL) Aggregate iterations B{C{i}}.
1108
- '''
1109
- if inst and i > 0:
1110
- inst._iteration += i
1111
-
1112
-
1113
1126
  def _3over(a, b):
1114
1127
  '''(INTERNAL) Return C{3 / (a * b)}.
1115
1128
  '''
1116
1129
  return _over(_3_0, a * b)
1117
1130
 
1118
1131
 
1119
- def _rC(unused, x, y):
1132
+ def _rC(x, y):
1120
1133
  '''(INTERNAL) Defined only for C{y != 0} and C{x >= 0}.
1121
1134
  '''
1122
- d = x - y
1123
- if d < 0: # catch NaN
1135
+ if x < y: # catch NaN
1124
1136
  # <https://DLMF.NIST.gov/19.2.E18>
1125
- d = -d
1137
+ d = y - x
1126
1138
  r = atan(sqrt(d / x)) if x > 0 else PI_2
1127
- elif d == 0: # XXX d < EPS0? or EPS02 or _EPSmin
1139
+ elif x == y: # XXX d < EPS0? or EPS02 or _EPSmin
1128
1140
  d, r = y, _1_0
1129
1141
  elif y > 0: # <https://DLMF.NIST.gov/19.2.E19>
1142
+ d = x - y
1130
1143
  r = asinh(sqrt(d / y)) # atanh(sqrt((x - y) / x))
1131
1144
  elif y < 0: # <https://DLMF.NIST.gov/19.2.E20>
1145
+ d = x - y
1132
1146
  r = asinh(sqrt(-x / y)) # atanh(sqrt(x / (x - y)))
1133
1147
  else: # PYCHOK no cover
1134
- raise _ellipticError(Elliptic.fRC, x, y)
1135
- return r / sqrt(d) # float
1148
+ d = 0 # y == 0
1149
+ if d > 0 and x >= 0:
1150
+ return r / sqrt(d) # float
1151
+ raise _ellipticError(Elliptic.fRC, x, y)
1136
1152
 
1137
1153
 
1138
- def _RD(inst, x, y, z, *over):
1154
+ def _RD(x, y, z, over=_1_0, inst=None):
1139
1155
  '''(INTERNAL) Carlson, eqs 2.28 - 2.34.
1140
1156
  '''
1141
1157
  L = _List(x, y, z)
1142
- S = _Dsum()
1143
- for a, m, r, s in L.amrs4(inst, True, _TolRF):
1158
+ S = Fsum()
1159
+ for a, m, r, s in L.amrs4(True, _TolRF, inst):
1144
1160
  if s:
1145
1161
  S += _over(_3_0, (r + z) * s[2] * m)
1146
1162
  z = L[2] # s[2] = sqrt(z)
@@ -1148,26 +1164,26 @@ def _RD(inst, x, y, z, *over):
1148
1164
  xy = x * y
1149
1165
  z = (x + y) / _3_0
1150
1166
  z2 = z**2
1151
- return _Horner(S(_1_0), sqrt(a) * a * m,
1167
+ return _Horner(S, sqrt(a) * a * m,
1152
1168
  (xy - z2 * _6_0),
1153
1169
  (xy * _3_0 - z2 * _8_0) * z,
1154
1170
  (xy - z2) * z2 * _3_0,
1155
- (xy * z2 * z), *over) # Fsum
1171
+ (xy * z2 * z), over) # Fsum
1156
1172
 
1157
1173
 
1158
- def _rF2(inst, x, y): # 2-arg version, z=0
1174
+ def _rF2(x, y, inst=None): # 2-arg version, z=0
1159
1175
  '''(INTERNAL) Carlson, eqs 2.36 - 2.38.
1160
1176
  '''
1161
- for a, b in _ab2(inst, x, y): # PYCHOK yield
1177
+ for a, b, _ in _ab3(x, y, inst): # PYCHOK yield
1162
1178
  pass
1163
1179
  return _over(PI, a + b) # float
1164
1180
 
1165
1181
 
1166
- def _RF3(inst, x, y, z): # 3-arg version
1182
+ def _RF3(x, y, z, inst=None): # 3-arg version
1167
1183
  '''(INTERNAL) Carlson, eqs 2.2 - 2.7.
1168
1184
  '''
1169
1185
  L = _List(x, y, z)
1170
- for a, m, _, _ in L.amrs4(inst, False, _TolRF):
1186
+ for a, m, _, _ in L.amrs4(False, _TolRF, inst):
1171
1187
  pass
1172
1188
  x, y = L.rescale(a * m, x, y)
1173
1189
  z = neg(x + y)
@@ -1185,33 +1201,32 @@ def _RF3(inst, x, y, z): # 3-arg version
1185
1201
  return S.fdiv(sqrt(a) * 240240) # Fsum
1186
1202
 
1187
1203
 
1188
- def _rG2(inst, x, y, PI_=PI_4): # 2-args
1204
+ def _rG2(x, y, inst=None, PI_=PI_4): # 2-args
1189
1205
  '''(INTERNAL) Carlson, eqs 2.36 - 2.39.
1190
1206
  '''
1191
- m = -1 # neg!
1192
- S = None
1193
- for a, b in _ab2(inst, x, y): # PYCHOK yield
1194
- if S is None: # initial
1195
- S = _Dsum()
1196
- S += (a + b)**2 * _0_5
1197
- else:
1198
- S += (a - b)**2 * m
1207
+ m = 1
1208
+ S = Fsum()
1209
+ for a, b, i in _ab3(x, y, inst): # PYCHOK yield
1210
+ if i:
1211
+ S -= (a - b)**2 * m
1199
1212
  m *= 2
1200
- return S(PI_).fover(a + b)
1213
+ else:
1214
+ S += (a + b)**2 * _0_5
1215
+ return S.fmul(PI_).fover(a + b) # float
1201
1216
 
1202
1217
 
1203
- def _rG3(inst, x, y, z): # 3-arg version
1218
+ def _rG3(x, y, z): # 3-arg version
1204
1219
  '''(INTERNAL) C{x}, C{y} and C{z} all non-zero, see C{.fRG}.
1205
1220
  '''
1206
- R = _RF3(inst, x, y, z) * z
1221
+ R = _RF3(x, y, z) * z
1207
1222
  rd = (x - z) * (z - y) # - (y - z)
1208
1223
  if rd: # Carlson, eq 1.7
1209
- R += _RD(inst, x, y, z, _3_0 / rd)
1224
+ R += _RD(x, y, z, _3_0 / rd)
1210
1225
  R += sqrt(x * y / z)
1211
- return R.fover(_2_0)
1226
+ return R.fover(_2_0) # float
1212
1227
 
1213
1228
 
1214
- def _RJ(inst, x, y, z, p, *over):
1229
+ def _RJ(x, y, z, p, over=_1_0, inst=None):
1215
1230
  '''(INTERNAL) Carlson, eqs 2.17 - 2.25.
1216
1231
  '''
1217
1232
  def _xyzp(x, y, z, p):
@@ -1219,17 +1234,17 @@ def _RJ(inst, x, y, z, p, *over):
1219
1234
 
1220
1235
  L = _List(x, y, z, p)
1221
1236
  n = neg(_xyzp(x, y, z, -p))
1222
- S = _Dsum()
1223
- for a, m, _, s in L.amrs4(inst, True, _TolRD):
1237
+ S = Fsum()
1238
+ for a, m, _, s in L.amrs4(True, _TolRD, inst):
1224
1239
  if s:
1225
1240
  d = _xyzp(*s)
1226
1241
  if d:
1227
1242
  if n:
1228
- rc = _rC(inst, _1_0, n / d**2 + _1_0)
1229
- n = n / _64_0 # /= chokes PyChecker
1243
+ r = _rC(_1_0, (n / d**2 + _1_0))
1244
+ n = n / _64_0 # /= chokes PyChecker
1230
1245
  else:
1231
- rc = _1_0 # == _rC(None, _1_0, _1_0)
1232
- S += rc / (d * m)
1246
+ r = _1_0 # == _rC(_1_0, _1_0)
1247
+ S += r / (d * m)
1233
1248
  else: # PYCHOK no cover
1234
1249
  return NAN
1235
1250
  x, y, z = L.rescale(a * m, x, y, z)
@@ -1239,10 +1254,21 @@ def _RJ(inst, x, y, z, p, *over):
1239
1254
  E2 = Fsum(x * y, x * z, y * z, -p2 * _3_0)
1240
1255
  E2p = E2 * p
1241
1256
  xyz = x * y * z
1242
- return _Horner(S(_6_0), sqrt(a) * a * m, E2,
1257
+ return _Horner(S.fmul(_6_0), sqrt(a) * a * m, E2,
1243
1258
  Fsum(p3 * _4_0, xyz, E2p * _2_0),
1244
1259
  Fsum(p3 * _3_0, E2p, xyz * _2_0).fmul(p),
1245
- xyz * p2, *over) # Fsum
1260
+ xyz * p2, over) # Fsum
1261
+
1262
+
1263
+ class _RJfma(object):
1264
+ '''(INTERNAL) Carlson, "fma"able.
1265
+ '''
1266
+ def __init__(self, *args):
1267
+ self._Rj = _RJ(*args)
1268
+
1269
+ def ma(self, b, c):
1270
+ r = fma(self._Rj, b, c)
1271
+ return float(r)
1246
1272
 
1247
1273
  # **) MIT License
1248
1274
  #