00001
00002
00003
00004
00005
00006 namespace NewGamePhysics.Mathematics
00007 {
00008 using System;
00009
00015 public static class Legendre
00016 {
00020 private static double[] f1;
00021
00025 private static double[] f2;
00026
00030 private static double[] sqr;
00031
00035 private static int lmax_old = -1;
00036
00044 public static double Polynomial(int n, double x)
00045 {
00046 if (n < 0)
00047 {
00048 throw new ArgumentOutOfRangeException("n");
00049 }
00050
00051 if ((x < -1.0) || (x > 1.0))
00052 {
00053 throw new ArgumentOutOfRangeException("x");
00054 }
00055
00056 double x2, x4, x6, x8, x10, x12, x14, x16, x18;
00057
00058 switch (n)
00059 {
00060 case 0:
00061 return (1.0);
00062 case 1:
00063 return (x);
00064 case 2:
00065 x2 = x * x;
00066 return ((3.0 * x2 - 1.0) * 0.5);
00067 case 3:
00068 x2 = x * x;
00069 return (x * (5.0 * x2 - 3.0) * 0.5);
00070 case 4:
00071 x2 = x * x;
00072 x4 = x2 * x2;
00073 return ((35.0 * x4 - 30.0 * x2 + 3.0) * 0.125);
00074 case 5:
00075 x2 = x * x;
00076 x4 = x2 * x2;
00077 return (x * (63.0 * x4 - 70.0 * x2 + 15.0) * 0.125);
00078 case 6:
00079 x2 = x * x;
00080 x4 = x2 * x2;
00081 x6 = x4 * x2;
00082 return ((231.0 * x6 - 315.0 * x4 + 105.0 * x2 - 5.0) * 0.0625);
00083 case 7:
00084 x2 = x * x;
00085 x4 = x2 * x2;
00086 x6 = x4 * x2;
00087 return (x * (429.0 * x6 - 693.0 * x4 + 315.0 * x2 - 35.0) * 0.0625);
00088 case 8:
00089 x2 = x * x;
00090 x4 = x2 * x2;
00091 x6 = x4 * x2;
00092 x8 = x6 * x2;
00093 return ((6435.0 * x8 - 12012.0 * x6 + 6930.0 * x4 - 1260.0 * x2 + 35.0) * 0.0078125);
00094 case 9:
00095 x2 = x * x;
00096 x4 = x2 * x2;
00097 x6 = x4 * x2;
00098 x8 = x6 * x2;
00099 return (x * (12155.0 * x8 - 25740.0 * x6 + 18018.0 * x4 - 4620.0 * x2 + 315.0) * 0.0078125);
00100 case 10:
00101 x2 = x * x;
00102 x4 = x2 * x2;
00103 x6 = x4 * x2;
00104 x8 = x6 * x2;
00105 x10 = x8 * x2;
00106 return ((46189.0 * x10 - 109395.0 * x8 + 90090.0 * x6 - 30030.0 * x4 + 3465.0 * x2 - 63.0) * 0.00390625);
00107 case 11:
00108 x2 = x * x;
00109 x4 = x2 * x2;
00110 x6 = x4 * x2;
00111 x8 = x6 * x2;
00112 x10 = x8 * x2;
00113 return (x * (88179.0 * x10 - 230945.0 * x8 + 218790.0 * x6 - 90090.0 * x4 + 15015.0 * x2 - 693.0) * 0.00390625);
00114 case 12:
00115 x2 = x * x;
00116 x4 = x2 * x2;
00117 x6 = x4 * x2;
00118 x8 = x6 * x2;
00119 x10 = x8 * x2;
00120 x12 = x10 * x2;
00121 return ((676039.0 * x12 - 1939938.0 * x10 + 2078505.0 * x8 - 1021020.0 * x6 + 225225.0 * x4 - 18018.0 * x2 + 231.0) * 0.0009765625);
00122 case 13:
00123 x2 = x * x;
00124 x4 = x2 * x2;
00125 x6 = x4 * x2;
00126 x8 = x6 * x2;
00127 x10 = x8 * x2;
00128 x12 = x10 * x2;
00129 return (x * (1300075.0 * x12 - 4056234.0 * x10 + 4849845.0 * x8 - 2771340.0 * x6 + 765765.0 * x4 - 90090.0 * x2 + 3003.0) * 0.0009765625);
00130 case 14:
00131 x2 = x * x;
00132 x4 = x2 * x2;
00133 x6 = x4 * x2;
00134 x8 = x6 * x2;
00135 x10 = x8 * x2;
00136 x12 = x10 * x2;
00137 x14 = x12 * x2;
00138 return ((5014575.0 * x14 - 16900975.0 * x12 + 22309287.0 * x10 - 14549535.0 * x8 + 4849845.0 * x6 - 765765.0 * x4 + 45045.0 * x2 - 429.0) * 0.00048828125);
00139 case 15:
00140 x2 = x * x;
00141 x4 = x2 * x2;
00142 x6 = x4 * x2;
00143 x8 = x6 * x2;
00144 x10 = x8 * x2;
00145 x12 = x10 * x2;
00146 x14 = x12 * x2;
00147 return (x * (9694845.0 * x14 - 35102025.0 * x12 + 50702925.0 * x10 - 37182145.0 * x8 + 14549535.0 * x6 - 2909907.0 * x4 + 255255.0 * x2 - 6435.0) * 0.00048828125);
00148 case 16:
00149 x2 = x * x;
00150 x4 = x2 * x2;
00151 x6 = x4 * x2;
00152 x8 = x6 * x2;
00153 x10 = x8 * x2;
00154 x12 = x10 * x2;
00155 x14 = x12 * x2;
00156 x16 = x14 * x2;
00157 return ((300540195.0 * x16 - 1163381400.0 * x14 + 1825305300.0 * x12 - 1487285800.0 * x10 + 669278610.0 * x8 - 162954792.0 * x6 + 19399380.0 * x4 - 875160.0 * x2 + 6435.0) * 3.0517578125e-05);
00158 case 17:
00159 x2 = x * x;
00160 x4 = x2 * x2;
00161 x6 = x4 * x2;
00162 x8 = x6 * x2;
00163 x10 = x8 * x2;
00164 x12 = x10 * x2;
00165 x14 = x12 * x2;
00166 x16 = x14 * x2;
00167 return (x * (583401555.0 * x16 - 2404321560.0 * x14 + 4071834900.0 * x12 - 3650610600.0 * x10 + 1859107250.0 * x8 - 535422888.0 * x6 + 81477396.0 * x4 - 5542680.0 * x2 + 109395.0) * 3.0517578125e-05);
00168 case 18:
00169 x2 = x * x;
00170 x4 = x2 * x2;
00171 x6 = x4 * x2;
00172 x8 = x6 * x2;
00173 x10 = x8 * x2;
00174 x12 = x10 * x2;
00175 x14 = x12 * x2;
00176 x16 = x14 * x2;
00177 x18 = x16 * x2;
00178 return ((2268783825.0 * x18 - 9917826435.0 * x16 + 18032411700.0 * x14 - 17644617900.0 * x12 + 10039179150.0 * x10 - 3346393050.0 * x8 + 624660036.0 * x6 - 58198140.0 * x4 + 2078505.0 * x2 - 12155.0) * 1.52587890625e-05);
00179 case 19:
00180 x2 = x * x;
00181 x4 = x2 * x2;
00182 x6 = x4 * x2;
00183 x8 = x6 * x2;
00184 x10 = x8 * x2;
00185 x12 = x10 * x2;
00186 x14 = x12 * x2;
00187 x16 = x14 * x2;
00188 x18 = x16 * x2;
00189 return (x * (4418157975.0 * x18 - 20419054425.0 * x16 + 39671305740.0 * x14 - 42075627300.0 * x12 + 26466926850.0 * x10 - 10039179150.0 * x8 + 2230928700.0 * x6 - 267711444.0 * x4 + 14549535.0 * x2 - 230945.0) * 1.52587890625e-05);
00190 default:
00191 double result = 1;
00192 double a = 1;
00193 double b = x;
00194 for (int i = 2; i <= n; i++)
00195 {
00196 result = ((double)(2 * i - 1) * x * b - (double)(i - 1) * a) / (double)i;
00197 a = b;
00198 b = result;
00199 }
00200 return result;
00201 }
00202 }
00203
00216 public static double AssociatedFunction(int l, int m, double x)
00217 {
00218 if (l < 0)
00219 {
00220 throw new ArgumentOutOfRangeException("l");
00221 }
00222
00223 if ((m < 0) || (m > l))
00224 {
00225 throw new ArgumentOutOfRangeException("m");
00226 }
00227
00228 if ((x < -1.0) || (x > 1.0))
00229 {
00230 throw new ArgumentOutOfRangeException("x");
00231 }
00232
00233 double p = 1.0;
00234 if (m > 0)
00235 {
00236 double h = Math.Sqrt((1.0 - x) * (1.0 + x));
00237 double f = 1.0;
00238 for (int i = 1; i <= m; i++)
00239 {
00240 p *= (-f * h);
00241 f += 2.0;
00242 }
00243 }
00244 if (l == m)
00245 {
00246 return p;
00247 }
00248 else
00249 {
00250 double pp = x * (double)(2 * m + 1) * p;
00251 if (l == (m + 1))
00252 {
00253 return pp;
00254 }
00255 else
00256 {
00257 double pll = 0.0;
00258 for (int ll = m + 2; ll <= l; ll++)
00259 {
00260 pll = (x * (double)(2 * ll - 1) * pp - (double)(ll + m - 1) * p) / (double)(ll - m);
00261 p = pp;
00262 pp = pll;
00263 }
00264 return pll;
00265 }
00266 }
00267 }
00268
00282 public static double AssociatedFunctionShodor(int l, int m, double x)
00283 {
00284 if (l < 0)
00285 {
00286 throw new ArgumentOutOfRangeException("l");
00287 }
00288
00289 if ((m < 0) || (m > l))
00290 {
00291 throw new ArgumentOutOfRangeException("m");
00292 }
00293
00294 if ((x < -1.0) || (x > 1.0))
00295 {
00296 throw new ArgumentOutOfRangeException("x");
00297 }
00298
00299 double last, current, next;
00300 if (l < m)
00301 {
00302 current = 0.0;
00303 }
00304 else if ((l == m) && (m == 0))
00305 {
00306 current = 1.0;
00307 }
00308 else
00309 {
00310 last = 0.0;
00311 if (m == 0)
00312 {
00313 current = 1.0;
00314 }
00315 else
00316 {
00317 current =
00318 (double)Factorial.CalcDouble((int)(2 * m - 1)) *
00319 Math.Pow((1.0 - x * x), 0.5 * (double)m);
00320 }
00321 if (l != m)
00322 {
00323 for (int k = m; k < l; k++)
00324 {
00325 next =
00326 ((double)(2 * k + 1) * x * current -
00327 (double)(k + m) * last) / (double)(k + 1 - m);
00328 last = current;
00329 current = next;
00330 }
00331 }
00332 }
00333 return current;
00334 }
00335
00348 public static double AssociatedFunctionGsl(int l, int m, double x)
00349 {
00350 if (l < 0)
00351 {
00352 throw new ArgumentOutOfRangeException("l");
00353 }
00354
00355 if ((m < 0) || (m > l))
00356 {
00357 throw new ArgumentOutOfRangeException("m");
00358 }
00359
00360 if ((x < -1.0) || (x > 1.0))
00361 {
00362 throw new ArgumentOutOfRangeException("x");
00363 }
00364
00365 if (m == 0)
00366 {
00367 return Polynomial(l, x);
00368 }
00369 else
00370 {
00371 double mm = 1.0;
00372 if (m > 0)
00373 {
00374 double r = Math.Sqrt(1.0 - x) * Math.Sqrt(1.0 + x);
00375 double f = 1.0;
00376 for (int i = 1; i <= m; i++)
00377 {
00378 mm *= (-f * r);
00379 f += 2.0;
00380 }
00381 }
00382
00383 if (l == m)
00384 {
00385 return mm;
00386 }
00387
00388 double mpnm = (double)(2 * m + 1) * x * mm;
00389 if (l == (m + 1))
00390 {
00391 return mpnm;
00392 }
00393
00394 double nm2m = mm;
00395 double nmnm = mpnm;
00396 double nm = 0.0;
00397 for (int j = m + 2; j <= l; j++)
00398 {
00399 nm = ((double)(2 * j - 1) * x * nmnm - (double)(j + m - 1) * nm2m) / (double)(j - m);
00400 nm2m = nmnm;
00401 nmnm = nm;
00402 }
00403
00404 return nm;
00405 }
00406 }
00407
00408
00429 public static void NormalizedAssociatedFunctionAndDerivative(int lmax, double z, out double[][] value, out double[][] derivative)
00430 {
00431
00432
00433 double phase = 1.0;
00434
00435
00436 int cnorm = 0;
00437
00438
00439 double[] dp;
00440 double[] p;
00441 double pm1;
00442 double pm2;
00443 double pmm;
00444 double plm;
00445 double rescalem;
00446 double u;
00447 double u2;
00448 double scalef = 1.0e-280;
00449 int k;
00450 int kstart;
00451 int m;
00452 int mm;
00453 int l;
00454 int ll;
00455 int sqrdim;
00456 int sdim;
00457
00458
00459 if ((lmax < 0) || (lmax >2800))
00460 {
00461 throw new ArgumentOutOfRangeException("lmax");
00462 }
00463
00464 if (Math.Abs(z) >= 1.0)
00465 {
00466 throw new ArgumentOutOfRangeException("z");
00467 }
00468
00469
00470 sdim = (lmax + 1) * (lmax + 2) / 2;
00471 p = new double[sdim + 1];
00472 dp = new double[sdim + 1];
00473
00474
00475 if (lmax != lmax_old)
00476 {
00477 lmax_old = lmax;
00478
00479
00480 sqrdim = 2 * lmax + 1;
00481 sqr = new double[sqrdim + 1];
00482 for (l = 1; l <= sqrdim; l++)
00483 {
00484 sqr[l] = Math.Sqrt((double)l);
00485 }
00486
00487
00488 f1 = new double[sdim + 1];
00489 f2 = new double[sdim + 1];
00490 k = 3;
00491 for (l = 2; l <= lmax; l++)
00492 {
00493 k++;
00494 ll = 2 * l;
00495 f1[k] = sqr[ll - 1] * sqr[ll + 1] / (double)l;
00496 f2[k] = (double)(l - 1) * sqr[ll + 1] / sqr[ll - 3] / (double)l;
00497 for (m = 1; m <= (l - 2); m++)
00498 {
00499 k++;
00500 f1[k] = sqr[ll + 1] * sqr[ll - 1] / sqr[l + m] / sqr[l - m];
00501 f2[k] = sqr[ll + 1] * sqr[l - m - 1] * sqr[l + m - 1] / sqr[ll - 3] / sqr[l + m] / sqr[l - m];
00502 }
00503 k += 2;
00504 }
00505 }
00506
00507
00508 pm2 = 1.0;
00509 p[1] = 1.0;
00510 dp[1] = 0.0;
00511
00512 if (lmax > 0)
00513 {
00514
00515 pm1 = sqr[3] * z;
00516 p[2] = pm1;
00517 dp[2] = sqr[3];
00518
00519 u = Math.Sqrt((1.0 - z) * (1.0 + z));
00520 u2 = u * u;
00521
00522 k = 2;
00523 for (l = 2; l <= lmax; l++)
00524 {
00525 k = k + l;
00526 ll = 2 * l;
00527 plm = f1[k] * z * pm1 - f2[k] * pm2;
00528 p[k] = plm;
00529 dp[k] = (double)l * (sqr[ll + 1] / sqr[ll - 1] * pm1 - z * plm) / u2;
00530 pm2 = pm1;
00531 pm1 = plm;
00532 }
00533
00534
00535 if (cnorm == 1)
00536 {
00537 pmm = scalef;
00538 }
00539 else
00540 {
00541 pmm = sqr[2] * scalef;
00542 }
00543
00544 rescalem = 1.0 / scalef;
00545 kstart = 1;
00546 for (m = 1; m <= (lmax - 1); m++)
00547 {
00548 mm = 2 * m;
00549 rescalem = rescalem * u;
00550
00551
00552 kstart = kstart + m + 1;
00553 pmm = phase * pmm * sqr[mm + 1] / sqr[mm];
00554 p[kstart] = pmm * rescalem;
00555 dp[kstart] = -1.0 * (double)m * z * p[kstart] / u2;
00556 pm2 = pmm;
00557
00558
00559 k = kstart + m + 1;
00560 pm1 = z * sqr[mm + 3] * pmm;
00561 p[k] = pm1 * rescalem;
00562 dp[k] = (sqr[mm + 3] * p[k - m - 1] - z * (double)(m + 1) * p[k]) / u2;
00563
00564
00565 for (l = m + 2; l <= lmax; l++)
00566 {
00567 k += l;
00568 ll = 2 * l;
00569 plm = z * f1[k] * pm1 - f2[k] * pm2;
00570 p[k] = plm * rescalem;
00571 dp[k] = (sqr[ll + 1] * sqr[l - m] * sqr[l + m] / sqr[ll - 1] * p[k - l] - z * (double)l * p[k]) / u2;
00572 pm2 = pm1;
00573 pm1 = plm;
00574 }
00575 }
00576
00577
00578 rescalem = rescalem * u;
00579 kstart = kstart + m + 1;
00580 pmm = phase * pmm * sqr[2 * lmax + 1] / sqr[2 * lmax];
00581 p[kstart] = pmm * rescalem;
00582 dp[kstart] = -1.0 * (double)lmax * z * p[kstart] / u2;
00583 }
00584
00585
00586
00587 int i = 0;
00588 value = new double[lmax + 1][];
00589 derivative = new double[lmax + 1][];
00590 for (l = 0; l <= lmax; l++)
00591 {
00592 value[l] = new double[l + 1];
00593 derivative[l] = new double[l + 1];
00594 for (m = 0; m <= l; m++)
00595 {
00596 i++;
00597 value[l][m] = p[i];
00598 derivative[l][m] = dp[i];
00599 }
00600 }
00601 }
00602
00615 public static double SphericalAssociatedFunction(int l, int m, double theta)
00616 {
00617 if (l < 0)
00618 {
00619 throw new ArgumentOutOfRangeException("l");
00620 }
00621
00622 if ((m < 0) || (m > l))
00623 {
00624 throw new ArgumentOutOfRangeException("m");
00625 }
00626
00627 double x = Math.Cos(theta);
00628
00629 if (m == 0)
00630 {
00631 double p = Polynomial(l, x);
00632 double f = Math.Sqrt((double)(2 * l + 1) / (4.0 * Math.PI));
00633 p *= f;
00634 return p;
00635 }
00636 else if ((x == -1.0) || (x == 1.0))
00637 {
00638 return 0.0;
00639 }
00640 else
00641 {
00642 double sgn = ((m % 2) == 1) ? -1.0 : 1.0;
00643 double ympnmf = x * Math.Sqrt((double)(2 * m + 3));
00644 double lnc = Math.Log(1.0 - x * x);
00645 double lnp = Gamma.LogFunction((double)m + 0.5) - Gamma.LogFunction((double)m);
00646 double lnpre = -0.25 * Math.Log(Math.PI) + 0.5 * (lnp + (double)m * lnc);
00647 double sr = Math.Sqrt((2.0 + 1.0 / (double)m) / (4.0 * Math.PI));
00648 double ymm = sgn * sr * Math.Exp(lnpre);
00649 double ympnm = ympnmf * ymm;
00650
00651 if (l == m)
00652 {
00653 return ymm;
00654 }
00655 else if (l == (m + 1))
00656 {
00657 return ympnm;
00658 }
00659 else
00660 {
00661 double ynm = 0.0;
00662 for (int i = m + 2; i <= l; i++)
00663 {
00664 double r1 = (double)(i - m) / (double)(i + m);
00665 double r2 = (double)(i - m - 1) / (double)(i + m - 1);
00666 double f1 = Math.Sqrt(r1 * (double)(2 * i + 1) * (double)(2 * i - 1));
00667 double f2 = Math.Sqrt(r1 * r2 * (double)(2 * i + 1) / (double)(2 * i - 3));
00668 ynm = (x * ympnm * f1 - (double)(i + m - 1) * ymm * f2) / (double)(i - m);
00669 ymm = ympnm;
00670 ympnm = ynm;
00671 }
00672 return ynm;
00673 }
00674 }
00675 }
00676
00687 public static double Sum(
00688 int n,
00689 double x,
00690 double[] c
00691 )
00692 {
00693 if (n < 0)
00694 {
00695 throw new ArgumentOutOfRangeException("n");
00696 }
00697
00698 if ((n + 1) > c.Length)
00699 {
00700 throw new ArgumentOutOfRangeException("c", "Not enough coefficients");
00701 }
00702
00703 if ((x < -1.0) || (x > 1.0))
00704 {
00705 throw new ArgumentOutOfRangeException("x");
00706 }
00707
00708 double result = 0;
00709 double b1 = 0;
00710 double b2 = 0;
00711
00712 b1 = 0;
00713 b2 = 0;
00714 for (int i = n; i >= 0; i--)
00715 {
00716 result = (2 * i + 1) * x * b1 / (i + 1) - (i + 1) * b2 / (i + 2) + c[i];
00717 b2 = b1;
00718 b1 = result;
00719 }
00720
00721 return result;
00722 }
00723
00731 public static double[] Coefficients(int n)
00732 {
00733 if (n < 0)
00734 {
00735 throw new ArgumentOutOfRangeException("n");
00736 }
00737
00738 int i;
00739 double[] c = new double[n + 1];
00740 for (i = 0; i <= n; i++)
00741 {
00742 c[i] = 0;
00743 }
00744
00745 c[n] = 1;
00746 for (i = 1; i <= n; i++)
00747 {
00748 c[n] = c[n] * (n + i) / 2 / i;
00749 }
00750
00751 for (i = 0; i <= n / 2 - 1; i++)
00752 {
00753 c[n - 2 * (i + 1)] = -(c[n - 2 * i] * (n - 2 * i) * (n - 2 * i - 1) / 2 / (i + 1) / (2 * (n - i) - 1));
00754 }
00755 return c;
00756 }
00757 }
00758 }