RfRealDuplication.java

  1. /*
  2.  * Licensed to the Hipparchus project under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The Hipparchus project licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.hipparchus.special.elliptic.carlson;

  18. import org.hipparchus.util.FastMath;
  19. import org.hipparchus.util.MathArrays;

  20. /** Duplication algorithm for Carlson R<sub>F</sub> elliptic integral.
  21.  * @since 2.0
  22.  */
  23. class RfRealDuplication extends RealDuplication {

  24.     /** Max number of iterations in the AGM scale. */
  25.     static final int AGM_MAX = 32;

  26.     /** Constant term in R<sub>F</sub> polynomial. */
  27.     static final double CONSTANT = 240240;

  28.     /** Coefficient of E₂ in R<sub>F</sub> polynomial. */
  29.     static final double E2 = -24024;

  30.     /** Coefficient of E₃ in R<sub>F</sub> polynomial. */
  31.     static final double E3 = 17160;

  32.     /** Coefficient of E₂² in R<sub>F</sub> polynomial. */
  33.     static final double E2_E2 = 10010;

  34.     /** Coefficient of E₂E₃ in R<sub>F</sub> polynomial. */
  35.     static final double E2_E3 = -16380;

  36.     /** Coefficient of E₃² in R<sub>F</sub> polynomial. */
  37.     static final double E3_E3 = 6930;

  38.     /** Coefficient of E₂³ in R<sub>F</sub> polynomial. */
  39.     static final double E2_E2_E2 = -5775;

  40.     /** Denominator in R<sub>F</sub> polynomial. */
  41.     static final double DENOMINATOR = 240240;

  42.     /** Simple constructor.
  43.      * @param x first symmetric variable of the integral
  44.      * @param y second symmetric variable of the integral
  45.      * @param z third symmetric variable of the integral
  46.      */
  47.     RfRealDuplication(final double x, final double y, final double z) {
  48.         super(x, y, z);
  49.     }

  50.     /** {@inheritDoc} */
  51.     @Override
  52.     protected void initialMeanPoint(final double[] va) {
  53.         va[3] = (va[0] + va[1] + va[2]) / 3.0;
  54.     }

  55.     /** {@inheritDoc} */
  56.     @Override
  57.     protected double convergenceCriterion(final double r, final double max) {
  58.         return max / FastMath.sqrt(FastMath.sqrt(FastMath.sqrt(r * 3.0)));
  59.     }

  60.     /** {@inheritDoc} */
  61.     @Override
  62.     protected void update(final int m, final double[] vaM, final double[] sqrtM, final  double fourM) {

  63.         // equation 2.3 in Carlson[1995]
  64.         final double lambdaA = sqrtM[0] * sqrtM[1];
  65.         final double lambdaB = sqrtM[0] * sqrtM[2];
  66.         final double lambdaC = sqrtM[1] * sqrtM[2];

  67.         // equations 2.3 and 2.4 in Carlson[1995]
  68.         vaM[0] = MathArrays.linearCombination(0.25, vaM[0], 0.25, lambdaA, 0.25, lambdaB, 0.25, lambdaC); // xₘ
  69.         vaM[1] = MathArrays.linearCombination(0.25, vaM[1], 0.25, lambdaA, 0.25, lambdaB, 0.25, lambdaC); // yₘ
  70.         vaM[2] = MathArrays.linearCombination(0.25, vaM[2], 0.25, lambdaA, 0.25, lambdaB, 0.25, lambdaC); // zₘ
  71.         vaM[3] = MathArrays.linearCombination(0.25, vaM[3], 0.25, lambdaA, 0.25, lambdaB, 0.25, lambdaC); // aₘ

  72.     }

  73.     /** {@inheritDoc} */
  74.     @Override
  75.     protected double evaluate(final double[] va0, final double aM, final  double fourM) {

  76.         // compute symmetric differences
  77.         final double inv  = 1.0 / (aM * fourM);
  78.         final double bigX = (va0[3] - va0[0]) * inv;
  79.         final double bigY = (va0[3] - va0[1]) * inv;
  80.         final double bigZ = -(bigX + bigY);

  81.         // compute elementary symmetric functions (we already know e1 = 0 by construction)
  82.         final double e2  = bigX * bigY - bigZ * bigZ;
  83.         final double e3  = bigX * bigY * bigZ;

  84.         final double e2e2   =   e2 * e2;
  85.         final double e2e3   =   e2 * e3;
  86.         final double e3e3   =   e3 * e3;
  87.         final double e2e2e2 = e2e2 * e2;

  88.         // evaluate integral using equation 19.36.1 in DLMF
  89.         // (which add more terms than equation 2.7 in Carlson[1995])
  90.         final double poly = (e2e2e2 * E2_E2_E2 +
  91.                              e3e3   * E3_E3 +
  92.                              e2e3   * E2_E3 +
  93.                              e2e2   * E2_E2 +
  94.                              e3     * E3 +
  95.                              e2     * E2 +
  96.                              CONSTANT) /
  97.                         DENOMINATOR;
  98.         return poly / FastMath.sqrt(aM);

  99.     }

  100.     /** {@inheritDoc} */
  101.     @Override
  102.     public double integral() {
  103.         final double x = getVi(0);
  104.         final double y = getVi(1);
  105.         final double z = getVi(2);
  106.         if (x == 0) {
  107.             return completeIntegral(y, z);
  108.         } else if (y == 0) {
  109.             return completeIntegral(x, z);
  110.         } else if (z == 0) {
  111.             return completeIntegral(x, y);
  112.         } else {
  113.             return super.integral();
  114.         }
  115.     }

  116.     /** Compute Carlson complete elliptic integral R<sub>F</sub>(u, v, 0).
  117.      * @param x first symmetric variable of the integral
  118.      * @param y second symmetric variable of the integral
  119.      * @return Carlson complete elliptic integral R<sub>F</sub>(u, v, 0)
  120.      */
  121.     private double completeIntegral(final double x, final double y) {

  122.         double xM = FastMath.sqrt(x);
  123.         double yM = FastMath.sqrt(y);

  124.         // iterate down
  125.         for (int i = 1; i < AGM_MAX; ++i) {

  126.             final double xM1 = xM;
  127.             final double yM1 = yM;

  128.             // arithmetic mean
  129.             xM = (xM1 + yM1) * 0.5;

  130.             // geometric mean
  131.             yM = FastMath.sqrt(xM1 * yM1);

  132.             // convergence (by the inequality of arithmetic and geometric means, this is non-negative)
  133.             if (FastMath.abs(xM - yM) <= 4 * FastMath.ulp(xM)) {
  134.                 // convergence has been reached
  135.                 break;
  136.             }

  137.         }

  138.         return FastMath.PI / (xM + yM);

  139.     }

  140. }