ellik.c
Go to the documentation of this file.
1 /* ellik.c
2  *
3  * Incomplete elliptic integral of the first kind
4  *
5  *
6  *
7  * SYNOPSIS:
8  *
9  * double phi, m, y, ellik();
10  *
11  * y = ellik( phi, m );
12  *
13  *
14  *
15  * DESCRIPTION:
16  *
17  * Approximates the integral
18  *
19  *
20  *
21  * phi
22  * -
23  * | |
24  * | dt
25  * F(phi | m) = | ------------------
26  * | 2
27  * | | sqrt( 1 - m sin t )
28  * -
29  * 0
30  *
31  * of amplitude phi and modulus m, using the arithmetic -
32  * geometric mean algorithm.
33  *
34  *
35  *
36  *
37  * ACCURACY:
38  *
39  * Tested at random points with m in [0, 1] and phi as indicated.
40  *
41  * Relative error:
42  * arithmetic domain # trials peak rms
43  * IEEE -10,10 200000 7.4e-16 1.0e-16
44  *
45  *
46  */
47 
48 
49 /*
50  * Cephes Math Library Release 2.0: April, 1987
51  * Copyright 1984, 1987 by Stephen L. Moshier
52  * Direct inquiries to 30 Frost Street, Cambridge, MA 02140
53  */
54 /* Copyright 2014, Eric W. Moore */
55 
56 /* Incomplete elliptic integral of first kind */
57 
58 #include "mconf.h"
59 extern double MACHEP;
60 
61 static double ellik_neg_m(double phi, double m);
62 
63 double ellik(double phi, double m)
64 {
65  double a, b, c, e, temp, t, K, denom, npio2;
66  int d, mod, sign;
67 
68  if (cephes_isnan(phi) || cephes_isnan(m))
69  return NAN;
70  if (m > 1.0)
71  return NAN;
72  if (cephes_isinf(phi) || cephes_isinf(m))
73  {
74  if (cephes_isinf(m) && cephes_isfinite(phi))
75  return 0.0;
76  else if (cephes_isinf(phi) && cephes_isfinite(m))
77  return phi;
78  else
79  return NAN;
80  }
81  if (m == 0.0)
82  return (phi);
83  a = 1.0 - m;
84  if (a == 0.0) {
85  if (fabs(phi) >= (double)M_PI_2) {
86  sf_error("ellik", SF_ERROR_SINGULAR, NULL);
87  return (INFINITY);
88  }
89  /* DLMF 19.6.8, and 4.23.42 */
90  return asinh(tan(phi));
91  }
92  npio2 = floor(phi / M_PI_2);
93  if (fmod(fabs(npio2), 2.0) == 1.0)
94  npio2 += 1;
95  if (npio2 != 0.0) {
96  K = ellpk(a);
97  phi = phi - npio2 * M_PI_2;
98  }
99  else
100  K = 0.0;
101  if (phi < 0.0) {
102  phi = -phi;
103  sign = -1;
104  }
105  else
106  sign = 0;
107  if (a > 1.0) {
108  temp = ellik_neg_m(phi, m);
109  goto done;
110  }
111  b = sqrt(a);
112  t = tan(phi);
113  if (fabs(t) > 10.0) {
114  /* Transform the amplitude */
115  e = 1.0 / (b * t);
116  /* ... but avoid multiple recursions. */
117  if (fabs(e) < 10.0) {
118  e = atan(e);
119  if (npio2 == 0)
120  K = ellpk(a);
121  temp = K - ellik(e, m);
122  goto done;
123  }
124  }
125  a = 1.0;
126  c = sqrt(m);
127  d = 1;
128  mod = 0;
129 
130  while (fabs(c / a) > MACHEP) {
131  temp = b / a;
132  phi = phi + atan(t * temp) + mod * M_PI;
133  denom = 1.0 - temp * t * t;
134  if (fabs(denom) > 10*MACHEP) {
135  t = t * (1.0 + temp) / denom;
136  mod = (phi + M_PI_2) / M_PI;
137  }
138  else {
139  t = tan(phi);
140  mod = (int)floor((phi - atan(t))/M_PI);
141  }
142  c = (a - b) / 2.0;
143  temp = sqrt(a * b);
144  a = (a + b) / 2.0;
145  b = temp;
146  d += d;
147  }
148 
149  temp = (atan(t) + mod * M_PI) / (d * a);
150 
151  done:
152  if (sign < 0)
153  temp = -temp;
154  temp += npio2 * K;
155  return (temp);
156 }
157 
158 /* N.B. This will evaluate its arguments multiple times. */
159 #define MAX3(a, b, c) (a > b ? (a > c ? a : c) : (b > c ? b : c))
160 
161 /* To calculate legendre's incomplete elliptical integral of the first kind for
162  * negative m, we use a power series in phi for small m*phi*phi, an asymptotic
163  * series in m for large m*phi*phi* and the relation to Carlson's symmetric
164  * integral of the first kind.
165  *
166  * F(phi, m) = sin(phi) * R_F(cos(phi)^2, 1 - m * sin(phi)^2, 1.0)
167  * = R_F(c-1, c-m, c)
168  *
169  * where c = csc(phi)^2. We use the second form of this for (approximately)
170  * phi > 1/(sqrt(DBL_MAX) ~ 1e-154, where csc(phi)^2 overflows. Elsewhere we
171  * use the first form, accounting for the smallness of phi.
172  *
173  * The algorithm used is described in Carlson, B. C. Numerical computation of
174  * real or complex elliptic integrals. (1994) https://arxiv.org/abs/math/9409227
175  * Most variable names reflect Carlson's usage.
176  *
177  * In this routine, we assume m < 0 and 0 > phi > pi/2.
178  */
179 double ellik_neg_m(double phi, double m)
180 {
181  double x, y, z, x1, y1, z1, A0, A, Q, X, Y, Z, E2, E3, scale;
182  int n = 0;
183  double mpp = (m*phi)*phi;
184 
185  if (-mpp < 1e-6 && phi < -m) {
186  return phi + (-mpp*phi*phi/30.0 + 3.0*mpp*mpp/40.0 + mpp/6.0)*phi;
187  }
188 
189  if (-mpp > 4e7) {
190  double sm = sqrt(-m);
191  double sp = sin(phi);
192  double cp = cos(phi);
193 
194  double a = log(4*sp*sm/(1+cp));
195  double b = -(1 + cp/sp/sp - a) / 4 / m;
196  return (a + b) / sm;
197  }
198 
199  if (phi > 1e-153 && m > -1e305) {
200  double s = sin(phi);
201  double csc2 = 1.0 / (s*s);
202  scale = 1.0;
203  x = 1.0 / (tan(phi) * tan(phi));
204  y = csc2 - m;
205  z = csc2;
206  }
207  else {
208  scale = phi;
209  x = 1.0;
210  y = 1 - m*scale*scale;
211  z = 1.0;
212  }
213 
214  if (x == y && x == z) {
215  return scale / sqrt(x);
216  }
217 
218  A0 = (x + y + z) / 3.0;
219  A = A0;
220  x1 = x; y1 = y; z1 = z;
221  /* Carlson gives 1/pow(3*r, 1.0/6.0) for this constant. if r == eps,
222  * it is ~338.38. */
223  Q = 400.0 * MAX3(fabs(A0-x), fabs(A0-y), fabs(A0-z));
224 
225  while (Q > fabs(A) && n <= 100) {
226  double sx = sqrt(x1);
227  double sy = sqrt(y1);
228  double sz = sqrt(z1);
229  double lam = sx*sy + sx*sz + sy*sz;
230  x1 = (x1 + lam) / 4.0;
231  y1 = (y1 + lam) / 4.0;
232  z1 = (z1 + lam) / 4.0;
233  A = (x1 + y1 + z1) / 3.0;
234  n += 1;
235  Q /= 4;
236  }
237  X = (A0 - x) / A / (1 << 2*n);
238  Y = (A0 - y) / A / (1 << 2*n);
239  Z = -(X + Y);
240 
241  E2 = X*Y - Z*Z;
242  E3 = X*Y*Z;
243 
244  return scale * (1.0 - E2/10.0 + E3/14.0 + E2*E2/24.0
245  - 3.0*E2*E3/44.0) / sqrt(A);
246 }
gtsam.examples.DogLegOptimizerExample.int
int
Definition: DogLegOptimizerExample.py:111
MACHEP
double MACHEP
Definition: const.c:54
s
RealScalar s
Definition: level1_cplx_impl.h:126
e
Array< double, 1, 3 > e(1./3., 0.5, 2.)
atan
const EIGEN_DEVICE_FUNC AtanReturnType atan() const
Definition: ArrayCwiseUnaryOps.h:283
cephes_isnan
#define cephes_isnan(x)
Definition: mconf.h:99
d
static const double d[K][N]
Definition: igam.h:11
ceres::sin
Jet< T, N > sin(const Jet< T, N > &f)
Definition: jet.h:439
c
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
b
Scalar * b
Definition: benchVecAdd.cpp:17
z1
Point2 z1
Definition: testTriangulationFactor.cpp:45
gtsam::Y
GaussianFactorGraphValuePair Y
Definition: HybridGaussianProductFactor.cpp:29
x
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
Definition: gnuplot_common_settings.hh:12
sign
const EIGEN_DEVICE_FUNC SignReturnType sign() const
Definition: ArrayCwiseUnaryOps.h:219
E2
E2
Definition: test_numpy_dtypes.cpp:103
log
const EIGEN_DEVICE_FUNC LogReturnType log() const
Definition: ArrayCwiseUnaryOps.h:128
X
#define X
Definition: icosphere.cpp:20
cephes_isinf
#define cephes_isinf(x)
Definition: mconf.h:100
A0
static const double A0[]
Definition: expn.h:5
Q
Quaternion Q
Definition: testQuaternion.cpp:27
MAX3
#define MAX3(a, b, c)
Definition: ellik.c:159
ceres::cos
Jet< T, N > cos(const Jet< T, N > &f)
Definition: jet.h:426
A
Matrix< SCALARA, Dynamic, Dynamic, opt_A > A
Definition: bench_gemm.cpp:48
boost::multiprecision::fabs
Real fabs(const Real &a)
Definition: boostmultiprec.cpp:119
n
int n
Definition: BiCGSTAB_simple.cpp:1
y1
double y1(double x)
Definition: j1.c:199
A
Definition: test_numpy_dtypes.cpp:298
Eigen::bfloat16_impl::fmod
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 fmod(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:567
scale
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy y set format x g set format y g set format x2 g set format y2 g set format z g set angles radians set nogrid set key title set key left top Right noreverse box linetype linewidth samplen spacing width set nolabel set noarrow set nologscale set logscale x set set pointsize set encoding default set nopolar set noparametric set set set set surface set nocontour set clabel set mapping cartesian set nohidden3d set cntrparam order set cntrparam linear set cntrparam levels auto set cntrparam points set size set set xzeroaxis lt lw set x2zeroaxis lt lw set yzeroaxis lt lw set y2zeroaxis lt lw set tics in set ticslevel set tics scale
Definition: gnuplot_common_settings.hh:54
ellik_neg_m
static double ellik_neg_m(double phi, double m)
Definition: ellik.c:179
ellpk
double ellpk(double x)
Definition: ellpk.c:97
x1
Pose3 x1
Definition: testPose3.cpp:663
pybind_wrapper_test_script.z
z
Definition: pybind_wrapper_test_script.py:61
m
Matrix3f m
Definition: AngleAxis_mimic_euler.cpp:1
tan
const EIGEN_DEVICE_FUNC TanReturnType tan() const
Definition: ArrayCwiseUnaryOps.h:269
y
Scalar * y
Definition: level1_cplx_impl.h:124
M_PI_2
#define M_PI_2
Definition: mconf.h:118
Eigen::Quaternion
The quaternion class used to represent 3D orientations and rotations.
Definition: ForwardDeclarations.h:293
a
ArrayXXi a
Definition: Array_initializer_list_23_cxx11.cpp:1
mconf.h
cephes_isfinite
#define cephes_isfinite(x)
Definition: mconf.h:101
K
#define K
Definition: igam.h:8
sf_error
void sf_error(const char *func_name, sf_error_t code, const char *fmt,...)
Definition: sf_error.c:41
ellik
double ellik(double phi, double m)
Definition: ellik.c:63
SF_ERROR_SINGULAR
@ SF_ERROR_SINGULAR
Definition: sf_error.h:10
NULL
#define NULL
Definition: ccolamd.c:609
M_PI
#define M_PI
Definition: mconf.h:117
align_3::t
Point2 t(10, 10)
Z
#define Z
Definition: icosphere.cpp:21
ceres::sqrt
Jet< T, N > sqrt(const Jet< T, N > &f)
Definition: jet.h:418
floor
const EIGEN_DEVICE_FUNC FloorReturnType floor() const
Definition: ArrayCwiseUnaryOps.h:481


gtsam
Author(s):
autogenerated on Sat Nov 16 2024 04:02:15