RealDuplication.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. /** Duplication algorithm for Carlson symmetric forms.
  20.  * <p>
  21.  * The algorithms are described in B. C. Carlson 1995 paper
  22.  * "Numerical computation of real or complex elliptic integrals", with
  23.  * improvements described in the appendix of B. C. Carlson and James FitzSimons
  24.  * 2000 paper "Reduction theorems for elliptic integrands with the square root
  25.  * of two quadratic factors". They are also described in
  26.  * <a href="https://dlmf.nist.gov/19.36#i">section 19.36(i)</a>
  27.  * of Digital Library of Mathematical Functions.
  28.  * </p>
  29.  * @since 2.0
  30.  */
  31. abstract class RealDuplication {

  32.     /** Max number of iterations. */
  33.     private static final int M_MAX = 16;

  34.     /** Symmetric variables of the integral, plus mean point. */
  35.     private final double[] initialVA;

  36.     /** Convergence criterion. */
  37.     private final double q;

  38.     /** Constructor.
  39.      * @param v symmetric variables of the integral
  40.      */
  41.     RealDuplication(final double... v) {

  42.         final int n = v.length;
  43.         initialVA = new double[n + 1];
  44.         System.arraycopy(v, 0, initialVA, 0, n);
  45.         initialMeanPoint(initialVA);

  46.         double max = 0;
  47.         final double a0 = initialVA[n];
  48.         for (final double vi : v) {
  49.             max = FastMath.max(max, FastMath.abs(a0 - vi));
  50.         }
  51.         this.q = convergenceCriterion(FastMath.ulp(1.0), max);

  52.     }

  53.     /** Get the i<sup>th</sup> symmetric variable.
  54.      * @param i index of the variable
  55.      * @return i<sup>th</sup> symmetric variable
  56.      */
  57.     protected double getVi(final int i) {
  58.         return initialVA[i];
  59.     }

  60.     /** Compute initial mean point.
  61.      * <p>
  62.      * The initial mean point is put as the last array element
  63.      * </>
  64.      * @param va symmetric variables of the integral (plus placeholder for initial mean point)
  65.      */
  66.     protected abstract void initialMeanPoint(double[] va);

  67.     /** Compute convergence criterion.
  68.      * @param r relative tolerance
  69.      * @param max max(|a0-v[i]|)
  70.      * @return convergence criterion
  71.      */
  72.     protected abstract double convergenceCriterion(double r, double max);

  73.     /** Update reduced variables in place.
  74.      * <ul>
  75.      *  <li>vₘ₊₁|i] ← (vₘ[i] + λₘ) / 4</li>
  76.      *  <li>aₘ₊₁ ← (aₘ + λₘ) / 4</li>
  77.      * </ul>
  78.      * @param m iteration index
  79.      * @param vaM reduced variables and mean point (updated in place)
  80.      * @param sqrtM square roots of reduced variables
  81.      * @param fourM 4<sup>m</sup>
  82.      */
  83.     protected abstract void update(int m, double[] vaM, double[] sqrtM, double fourM);

  84.     /** Evaluate integral.
  85.      * @param va0 initial symmetric variables and mean point of the integral
  86.      * @param aM reduced mean point
  87.      * @param fourM 4<sup>m</sup>
  88.      * @return integral value
  89.      */
  90.     protected abstract double evaluate(double[] va0, double aM, double fourM);

  91.     /** Compute Carlson elliptic integral.
  92.      * @return Carlson elliptic integral
  93.      */
  94.     public double integral() {

  95.         // duplication iterations
  96.         final int       n    = initialVA.length - 1;
  97.         final double[] vaM   = initialVA.clone();
  98.         final double[] sqrtM = new double[n];
  99.         double         fourM = 1.0;
  100.         for (int m = 0; m < M_MAX; ++m) {

  101.             if (m > 0 && q < fourM * FastMath.abs(vaM[n])) {
  102.                 // convergence reached
  103.                 break;
  104.             }

  105.             // apply duplication once more
  106.             // (we know that {Field}Complex.sqrt() returns the root with nonnegative real part)
  107.             for (int i = 0; i < n; ++i) {
  108.                 sqrtM[i] = FastMath.sqrt(vaM[i]);
  109.             }
  110.             update(m, vaM, sqrtM, fourM);

  111.             fourM *= 4;

  112.         }

  113.         return evaluate(initialVA, vaM[n], fourM);

  114.     }

  115. }