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
19 import java.util.Map;
20 import java.util.TreeMap;
21
22 import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
23 import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
24 import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
25 import org.apache.commons.math4.legacy.core.Pair;
26
27 /**
28 * Base class for rules that determines the integration nodes and their
29 * weights.
30 * Subclasses must implement the {@link #computeRule(int) computeRule} method.
31 *
32 * @param <T> Type of the number used to represent the points and weights of
33 * the quadrature rules.
34 *
35 * @since 3.1
36 */
37 public abstract class BaseRuleFactory<T extends Number> {
38 /** List of points and weights, indexed by the order of the rule. */
39 private final Map<Integer, Pair<T[], T[]>> pointsAndWeights
40 = new TreeMap<>();
41 /** Cache for double-precision rules. */
42 private final Map<Integer, Pair<double[], double[]>> pointsAndWeightsDouble
43 = new TreeMap<>();
44
45 /**
46 * Gets a copy of the quadrature rule with the given number of integration
47 * points.
48 *
49 * @param numberOfPoints Number of integration points.
50 * @return a copy of the integration rule.
51 * @throws NotStrictlyPositiveException if {@code numberOfPoints < 1}.
52 * @throws DimensionMismatchException if the elements of the rule pair do not
53 * have the same length.
54 */
55 public Pair<double[], double[]> getRule(int numberOfPoints) {
56
57 if (numberOfPoints <= 0) {
58 throw new NotStrictlyPositiveException(LocalizedFormats.NUMBER_OF_POINTS,
59 numberOfPoints);
60 }
61
62 // Try to obtain the rule from the cache.
63 Pair<double[], double[]> cached = pointsAndWeightsDouble.get(numberOfPoints);
64
65 if (cached == null) {
66 // Rule not computed yet.
67
68 // Compute the rule.
69 final Pair<T[], T[]> rule = getRuleInternal(numberOfPoints);
70 cached = convertToDouble(rule);
71
72 // Cache it.
73 pointsAndWeightsDouble.put(numberOfPoints, cached);
74 }
75
76 // Return a copy.
77 return new Pair<>(cached.getFirst().clone(),
78 cached.getSecond().clone());
79 }
80
81 /**
82 * Gets a rule.
83 * Synchronization ensures that rules will be computed and added to the
84 * cache at most once.
85 * The returned rule is a reference into the cache.
86 *
87 * @param numberOfPoints Order of the rule to be retrieved.
88 * @return the points and weights corresponding to the given order.
89 * @throws DimensionMismatchException if the elements of the rule pair do not
90 * have the same length.
91 */
92 protected synchronized Pair<T[], T[]> getRuleInternal(int numberOfPoints) {
93 final Pair<T[], T[]> rule = pointsAndWeights.get(numberOfPoints);
94 if (rule == null) {
95 addRule(computeRule(numberOfPoints));
96 // The rule should be available now.
97 return getRuleInternal(numberOfPoints);
98 }
99 return rule;
100 }
101
102 /**
103 * Stores a rule.
104 *
105 * @param rule Rule to be stored.
106 * @throws DimensionMismatchException if the elements of the pair do not
107 * have the same length.
108 */
109 protected void addRule(Pair<T[], T[]> rule) {
110 if (rule.getFirst().length != rule.getSecond().length) {
111 throw new DimensionMismatchException(rule.getFirst().length,
112 rule.getSecond().length);
113 }
114
115 pointsAndWeights.put(rule.getFirst().length, rule);
116 }
117
118 /**
119 * Computes the rule for the given order.
120 *
121 * @param numberOfPoints Order of the rule to be computed.
122 * @return the computed rule.
123 * @throws DimensionMismatchException if the elements of the pair do not
124 * have the same length.
125 */
126 protected abstract Pair<T[], T[]> computeRule(int numberOfPoints);
127
128 /**
129 * Converts the from the actual {@code Number} type to {@code double}.
130 *
131 * @param <T> Type of the number used to represent the points and
132 * weights of the quadrature rules.
133 * @param rule Points and weights.
134 * @return points and weights as {@code double}s.
135 */
136 private static <T extends Number> Pair<double[], double[]> convertToDouble(Pair<T[], T[]> rule) {
137 final T[] pT = rule.getFirst();
138 final T[] wT = rule.getSecond();
139
140 final int len = pT.length;
141 final double[] pD = new double[len];
142 final double[] wD = new double[len];
143
144 for (int i = 0; i < len; i++) {
145 pD[i] = pT[i].doubleValue();
146 wD[i] = wT[i].doubleValue();
147 }
148
149 return new Pair<>(pD, wD);
150 }
151 }