RfFieldDuplication.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.CalculusFieldElement;
  19. import org.hipparchus.complex.Complex;
  20. import org.hipparchus.complex.FieldComplex;
  21. import org.hipparchus.util.FastMath;

  22. /** Duplication algorithm for Carlson R<sub>F</sub> elliptic integral.
  23.  * @param <T> type of the field elements (really {@link Complex} or {@link FieldComplex})
  24.  * @since 2.0
  25.  */
  26. class RfFieldDuplication<T extends CalculusFieldElement<T>> extends FieldDuplication<T> {

  27.     /** Simple constructor.
  28.      * @param x first symmetric variable of the integral
  29.      * @param y second symmetric variable of the integral
  30.      * @param z third symmetric variable of the integral
  31.      */
  32.     RfFieldDuplication(final T x, final T y, final T z) {
  33.         super(x, y, z);
  34.     }

  35.     /** {@inheritDoc} */
  36.     @Override
  37.     protected void initialMeanPoint(final T[] va) {
  38.         va[3] = va[0].add(va[1]).add(va[2]).divide(3.0);
  39.     }

  40.     /** {@inheritDoc} */
  41.     @Override
  42.     protected T convergenceCriterion(final T r, final T max) {
  43.         return max.divide(FastMath.sqrt(FastMath.sqrt(FastMath.sqrt(r.multiply(3.0)))));
  44.     }

  45.     /** {@inheritDoc} */
  46.     @Override
  47.     protected void update(final int m, final T[] vaM, final T[] sqrtM, final  double fourM) {

  48.         // equation 2.3 in Carlson[1995]
  49.         final T lambdaA = sqrtM[0].multiply(sqrtM[1]);
  50.         final T lambdaB = sqrtM[0].multiply(sqrtM[2]);
  51.         final T lambdaC = sqrtM[1].multiply(sqrtM[2]);

  52.         // equations 2.3 and 2.4 in Carlson[1995]
  53.         vaM[0] = vaM[0].linearCombination(0.25, vaM[0], 0.25, lambdaA, 0.25, lambdaB, 0.25, lambdaC); // xₘ
  54.         vaM[1] = vaM[1].linearCombination(0.25, vaM[1], 0.25, lambdaA, 0.25, lambdaB, 0.25, lambdaC); // yₘ
  55.         vaM[2] = vaM[2].linearCombination(0.25, vaM[2], 0.25, lambdaA, 0.25, lambdaB, 0.25, lambdaC); // zₘ
  56.         vaM[3] = vaM[3].linearCombination(0.25, vaM[3], 0.25, lambdaA, 0.25, lambdaB, 0.25, lambdaC); // aₘ

  57.     }

  58.     /** {@inheritDoc} */
  59.     @Override
  60.     protected T evaluate(final T[] va0, final T aM, final  double fourM) {

  61.         // compute symmetric differences
  62.         final T inv  = aM.multiply(fourM).reciprocal();
  63.         final T bigX = va0[3].subtract(va0[0]).multiply(inv);
  64.         final T bigY = va0[3].subtract(va0[1]).multiply(inv);
  65.         final T bigZ = bigX.add(bigY).negate();

  66.         // compute elementary symmetric functions (we already know e1 = 0 by construction)
  67.         final T e2  = bigX.multiply(bigY).subtract(bigZ.multiply(bigZ));
  68.         final T e3  = bigX.multiply(bigY).multiply(bigZ);

  69.         final T e2e2   = e2.multiply(e2);
  70.         final T e2e3   = e2.multiply(e3);
  71.         final T e3e3   = e3.multiply(e3);
  72.         final T e2e2e2 = e2e2.multiply(e2);

  73.         // evaluate integral using equation 19.36.1 in DLMF
  74.         // (which add more terms than equation 2.7 in Carlson[1995])
  75.         final T poly = e2e2e2.multiply(RfRealDuplication.E2_E2_E2).
  76.                        add(e3e3.multiply(RfRealDuplication.E3_E3)).
  77.                        add(e2e3.multiply(RfRealDuplication.E2_E3)).
  78.                        add(e2e2.multiply(RfRealDuplication.E2_E2)).
  79.                        add(e3.multiply(RfRealDuplication.E3)).
  80.                        add(e2.multiply(RfRealDuplication.E2)).
  81.                        add(RfRealDuplication.CONSTANT).
  82.                        divide(RfRealDuplication.DENOMINATOR);
  83.         return poly.divide(FastMath.sqrt(aM));

  84.     }

  85.     /** {@inheritDoc} */
  86.     @Override
  87.     public T integral() {
  88.         final T x = getVi(0);
  89.         final T y = getVi(1);
  90.         final T z = getVi(2);
  91.         if (x.isZero()) {
  92.             return completeIntegral(y, z);
  93.         } else if (y.isZero()) {
  94.             return completeIntegral(x, z);
  95.         } else if (z.isZero()) {
  96.             return completeIntegral(x, y);
  97.         } else {
  98.             return super.integral();
  99.         }
  100.     }

  101.     /** Compute Carlson complete elliptic integral R<sub>F</sub>(u, v, 0).
  102.      * @param x first symmetric variable of the integral
  103.      * @param y second symmetric variable of the integral
  104.      * @return Carlson complete elliptic integral R<sub>F</sub>(u, v, 0)
  105.      */
  106.     private T completeIntegral(final T x, final T y) {

  107.         T xM = x.sqrt();
  108.         T yM = y.sqrt();

  109.         // iterate down
  110.         for (int i = 1; i < RfRealDuplication.AGM_MAX; ++i) {

  111.             final T xM1 = xM;
  112.             final T yM1 = yM;

  113.             // arithmetic mean
  114.             xM = xM1.add(yM1).multiply(0.5);

  115.             // geometric mean
  116.             yM = xM1.multiply(yM1).sqrt();

  117.             // convergence (by the inequality of arithmetic and geometric means, this is non-negative)
  118.             if (xM.subtract(yM).norm() <= 4 * FastMath.ulp(xM).getReal()) {
  119.                 // convergence has been reached
  120.                 break;
  121.             }

  122.         }

  123.         return xM.add(yM).reciprocal().multiply(xM.getPi());

  124.     }

  125. }