BaseRuleFactory.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) 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 ASF 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.  *      http://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.apache.commons.math4.legacy.analysis.integration.gauss;

  18. import java.util.Map;
  19. import java.util.TreeMap;

  20. import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
  21. import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
  22. import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
  23. import org.apache.commons.math4.legacy.core.Pair;

  24. /**
  25.  * Base class for rules that determines the integration nodes and their
  26.  * weights.
  27.  * Subclasses must implement the {@link #computeRule(int) computeRule} method.
  28.  *
  29.  * @param <T> Type of the number used to represent the points and weights of
  30.  * the quadrature rules.
  31.  *
  32.  * @since 3.1
  33.  */
  34. public abstract class BaseRuleFactory<T extends Number> {
  35.     /** List of points and weights, indexed by the order of the rule. */
  36.     private final Map<Integer, Pair<T[], T[]>> pointsAndWeights
  37.         = new TreeMap<>();
  38.     /** Cache for double-precision rules. */
  39.     private final Map<Integer, Pair<double[], double[]>> pointsAndWeightsDouble
  40.         = new TreeMap<>();

  41.     /**
  42.      * Gets a copy of the quadrature rule with the given number of integration
  43.      * points.
  44.      *
  45.      * @param numberOfPoints Number of integration points.
  46.      * @return a copy of the integration rule.
  47.      * @throws NotStrictlyPositiveException if {@code numberOfPoints < 1}.
  48.      * @throws DimensionMismatchException if the elements of the rule pair do not
  49.      * have the same length.
  50.      */
  51.     public Pair<double[], double[]> getRule(int numberOfPoints) {

  52.         if (numberOfPoints <= 0) {
  53.             throw new NotStrictlyPositiveException(LocalizedFormats.NUMBER_OF_POINTS,
  54.                                                    numberOfPoints);
  55.         }

  56.         // Try to obtain the rule from the cache.
  57.         Pair<double[], double[]> cached = pointsAndWeightsDouble.get(numberOfPoints);

  58.         if (cached == null) {
  59.             // Rule not computed yet.

  60.             // Compute the rule.
  61.             final Pair<T[], T[]> rule = getRuleInternal(numberOfPoints);
  62.             cached = convertToDouble(rule);

  63.             // Cache it.
  64.             pointsAndWeightsDouble.put(numberOfPoints, cached);
  65.         }

  66.         // Return a copy.
  67.         return new Pair<>(cached.getFirst().clone(),
  68.                                             cached.getSecond().clone());
  69.     }

  70.     /**
  71.      * Gets a rule.
  72.      * Synchronization ensures that rules will be computed and added to the
  73.      * cache at most once.
  74.      * The returned rule is a reference into the cache.
  75.      *
  76.      * @param numberOfPoints Order of the rule to be retrieved.
  77.      * @return the points and weights corresponding to the given order.
  78.      * @throws DimensionMismatchException if the elements of the rule pair do not
  79.      * have the same length.
  80.      */
  81.     protected synchronized Pair<T[], T[]> getRuleInternal(int numberOfPoints) {
  82.         final Pair<T[], T[]> rule = pointsAndWeights.get(numberOfPoints);
  83.         if (rule == null) {
  84.             addRule(computeRule(numberOfPoints));
  85.             // The rule should be available now.
  86.             return getRuleInternal(numberOfPoints);
  87.         }
  88.         return rule;
  89.     }

  90.     /**
  91.      * Stores a rule.
  92.      *
  93.      * @param rule Rule to be stored.
  94.      * @throws DimensionMismatchException if the elements of the pair do not
  95.      * have the same length.
  96.      */
  97.     protected void addRule(Pair<T[], T[]> rule) {
  98.         if (rule.getFirst().length != rule.getSecond().length) {
  99.             throw new DimensionMismatchException(rule.getFirst().length,
  100.                                                  rule.getSecond().length);
  101.         }

  102.         pointsAndWeights.put(rule.getFirst().length, rule);
  103.     }

  104.     /**
  105.      * Computes the rule for the given order.
  106.      *
  107.      * @param numberOfPoints Order of the rule to be computed.
  108.      * @return the computed rule.
  109.      * @throws DimensionMismatchException if the elements of the pair do not
  110.      * have the same length.
  111.      */
  112.     protected abstract Pair<T[], T[]> computeRule(int numberOfPoints);

  113.     /**
  114.      * Converts the from the actual {@code Number} type to {@code double}.
  115.      *
  116.      * @param <T> Type of the number used to represent the points and
  117.      * weights of the quadrature rules.
  118.      * @param rule Points and weights.
  119.      * @return points and weights as {@code double}s.
  120.      */
  121.     private static <T extends Number> Pair<double[], double[]> convertToDouble(Pair<T[], T[]> rule) {
  122.         final T[] pT = rule.getFirst();
  123.         final T[] wT = rule.getSecond();

  124.         final int len = pT.length;
  125.         final double[] pD = new double[len];
  126.         final double[] wD = new double[len];

  127.         for (int i = 0; i < len; i++) {
  128.             pD[i] = pT[i].doubleValue();
  129.             wD[i] = wT[i].doubleValue();
  130.         }

  131.         return new Pair<>(pD, wD);
  132.     }
  133. }