FieldDuplication.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.Field;
  20. import org.hipparchus.complex.Complex;
  21. import org.hipparchus.complex.FieldComplex;
  22. import org.hipparchus.util.FastMath;
  23. import org.hipparchus.util.MathArrays;

  24. /** Duplication algorithm for Carlson symmetric forms.
  25.  * <p>
  26.  * The algorithms are described in B. C. Carlson 1995 paper
  27.  * "Numerical computation of real or complex elliptic integrals", with
  28.  * improvements described in the appendix of B. C. Carlson and James FitzSimons
  29.  * 2000 paper "Reduction theorems for elliptic integrands with the square root
  30.  * of two quadratic factors". They are also described in
  31.  * <a href="https://dlmf.nist.gov/19.36#i">section 19.36(i)</a>
  32.  * of Digital Library of Mathematical Functions.
  33.  * </p>
  34.  * @param <T> type of the field elements (really {@link Complex} or {@link FieldComplex})
  35.  * @since 2.0
  36.  */
  37. abstract class FieldDuplication<T extends CalculusFieldElement<T>> {

  38.     /** Max number of iterations. */
  39.     private static final int M_MAX = 16;

  40.     /** Symmetric variables of the integral, plus mean point. */
  41.     private final T[] initialVA;

  42.     /** Convergence criterion. */
  43.     private final double q;

  44.     /** Constructor.
  45.      * @param v symmetric variables of the integral
  46.      */
  47.     @SafeVarargs
  48.     FieldDuplication(final T... v) {

  49.         final Field<T> field = v[0].getField();
  50.         final int n = v.length;
  51.         initialVA = MathArrays.buildArray(field, n + 1);
  52.         System.arraycopy(v, 0, initialVA, 0, n);
  53.         initialMeanPoint(initialVA);

  54.         T max = field.getZero();
  55.         final T a0 = initialVA[n];
  56.         for (final T vi : v) {
  57.             max = FastMath.max(max, a0.subtract(vi).abs());
  58.         }
  59.         this.q = convergenceCriterion(FastMath.ulp(field.getOne()), max).getReal();

  60.     }

  61.     /** Get the i<sup>th</sup> symmetric variable.
  62.      * @param i index of the variable
  63.      * @return i<sup>th</sup> symmetric variable
  64.      */
  65.     protected T getVi(final int i) {
  66.         return initialVA[i];
  67.     }

  68.     /** Compute initial mean point.
  69.      * <p>
  70.      * The initial mean point is put as the last array element
  71.      * </>
  72.      * @param va symmetric variables of the integral (plus placeholder for initial mean point)
  73.      */
  74.     protected abstract void initialMeanPoint(T[] va);

  75.     /** Compute convergence criterion.
  76.      * @param r relative tolerance
  77.      * @param max max(|a0-v[i]|)
  78.      * @return convergence criterion
  79.      */
  80.     protected abstract T convergenceCriterion(T r, T max);

  81.     /** Update reduced variables in place.
  82.      * <ul>
  83.      *  <li>vₘ₊₁|i] ← (vₘ[i] + λₘ) / 4</li>
  84.      *  <li>aₘ₊₁ ← (aₘ + λₘ) / 4</li>
  85.      * </ul>
  86.      * @param m iteration index
  87.      * @param vaM reduced variables and mean point (updated in place)
  88.      * @param sqrtM square roots of reduced variables
  89.      * @param fourM 4<sup>m</sup>
  90.      */
  91.     protected abstract void update(int m, T[] vaM, T[] sqrtM, double fourM);

  92.     /** Evaluate integral.
  93.      * @param va0 initial symmetric variables and mean point of the integral
  94.      * @param aM reduced mean point
  95.      * @param fourM 4<sup>m</sup>
  96.      * @return convergence criterion
  97.      */
  98.     protected abstract T evaluate(T[] va0, T aM, double fourM);

  99.     /** Compute Carlson elliptic integral.
  100.      * @return Carlson elliptic integral
  101.      */
  102.     public T integral() {

  103.         // duplication iterations
  104.         final int n     = initialVA.length - 1;
  105.         final T[] vaM   = initialVA.clone();
  106.         final T[] sqrtM = MathArrays.buildArray(initialVA[0].getField(), n);
  107.         double    fourM = 1.0;
  108.         for (int m = 0; m < M_MAX; ++m) {

  109.             if (m > 0 && q < fourM * vaM[n].norm()) {
  110.                 // convergence reached
  111.                 break;
  112.             }

  113.             // apply duplication once more
  114.             // (we know that {Field}Complex.sqrt() returns the root with nonnegative real part)
  115.             for (int i = 0; i < n; ++i) {
  116.                 sqrtM[i] = vaM[i].sqrt();
  117.             }
  118.             update(m, vaM, sqrtM, fourM);

  119.             fourM *= 4;

  120.         }

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

  122.     }

  123. }