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.transform;
18
19 import java.util.function.DoubleUnaryOperator;
20
21 import org.apache.commons.numbers.complex.Complex;
22
23 /**
24 * Useful functions for the implementation of various transforms.
25 * Class is package-private (for internal use only).
26 */
27 final class TransformUtils {
28 /** Number of array slots: 1 for "real" parts 1 for "imaginary" parts. */
29 private static final int NUM_PARTS = 2;
30
31 /** Utility class. */
32 private TransformUtils() {}
33
34 /**
35 * Multiply every component in the given real array by the
36 * given real number. The change is made in place.
37 *
38 * @param f Array to be scaled.
39 * @param d Scaling coefficient.
40 * @return a reference to the scaled array.
41 */
42 static double[] scaleInPlace(double[] f, double d) {
43 for (int i = 0; i < f.length; i++) {
44 f[i] *= d;
45 }
46 return f;
47 }
48
49 /**
50 * Multiply every component in the given complex array by the
51 * given real number. The change is made in place.
52 *
53 * @param f Array to be scaled.
54 * @param d Scaling coefficient.
55 * @return the scaled array.
56 */
57 static Complex[] scaleInPlace(Complex[] f, double d) {
58 for (int i = 0; i < f.length; i++) {
59 f[i] = Complex.ofCartesian(d * f[i].getReal(), d * f[i].getImaginary());
60 }
61 return f;
62 }
63
64
65 /**
66 * Builds a new two dimensional array of {@code double} filled with the real
67 * and imaginary parts of the specified {@link Complex} numbers. In the
68 * returned array {@code dataRI}, the data is laid out as follows
69 * <ul>
70 * <li>{@code dataRI[0][i] = dataC[i].getReal()},</li>
71 * <li>{@code dataRI[1][i] = dataC[i].getImaginary()}.</li>
72 * </ul>
73 *
74 * @param dataC Array of {@link Complex} data to be transformed.
75 * @return a two dimensional array filled with the real and imaginary parts
76 * of the specified complex input.
77 */
78 static double[][] createRealImaginary(final Complex[] dataC) {
79 final double[][] dataRI = new double[2][dataC.length];
80 final double[] dataR = dataRI[0];
81 final double[] dataI = dataRI[1];
82 for (int i = 0; i < dataC.length; i++) {
83 final Complex c = dataC[i];
84 dataR[i] = c.getReal();
85 dataI[i] = c.getImaginary();
86 }
87 return dataRI;
88 }
89
90 /**
91 * Builds a new array of {@link Complex} from the specified two dimensional
92 * array of real and imaginary parts. In the returned array {@code dataC},
93 * the data is laid out as follows
94 * <ul>
95 * <li>{@code dataC[i].getReal() = dataRI[0][i]},</li>
96 * <li>{@code dataC[i].getImaginary() = dataRI[1][i]}.</li>
97 * </ul>
98 *
99 * @param dataRI Array of real and imaginary parts to be transformed.
100 * @return a {@link Complex} array.
101 * @throws IllegalArgumentException if the number of rows of the specified
102 * array is not two, or the array is not rectangular.
103 */
104 static Complex[] createComplex(final double[][] dataRI) {
105 if (dataRI.length != NUM_PARTS) {
106 throw new TransformException(TransformException.SIZE_MISMATCH,
107 dataRI.length, NUM_PARTS);
108 }
109 final double[] dataR = dataRI[0];
110 final double[] dataI = dataRI[1];
111 if (dataR.length != dataI.length) {
112 throw new TransformException(TransformException.SIZE_MISMATCH,
113 dataI.length, dataR.length);
114 }
115
116 final int n = dataR.length;
117 final Complex[] c = new Complex[n];
118 for (int i = 0; i < n; i++) {
119 c[i] = Complex.ofCartesian(dataR[i], dataI[i]);
120 }
121 return c;
122 }
123
124 /**
125 * Samples the specified univariate real function on the specified interval.
126 * <p>
127 * The interval is divided equally into {@code n} sections and sample points
128 * are taken from {@code min} to {@code max - (max - min) / n}; therefore
129 * {@code f} is not sampled at the upper bound {@code max}.</p>
130 *
131 * @param f Function to be sampled
132 * @param min Lower bound of the interval (included).
133 * @param max Upper bound of the interval (excluded).
134 * @param n Number of sample points.
135 * @return the array of samples.
136 * @throws IllegalArgumentException if the lower bound {@code min} is
137 * greater than, or equal to the upper bound {@code max}, if the number
138 * of sample points {@code n} is negative.
139 */
140 static double[] sample(DoubleUnaryOperator f,
141 double min,
142 double max,
143 int n) {
144 if (n <= 0) {
145 throw new TransformException(TransformException.NOT_STRICTLY_POSITIVE,
146 Integer.valueOf(n));
147 }
148 if (min >= max) {
149 throw new TransformException(TransformException.TOO_LARGE, min, max);
150 }
151
152 final double[] s = new double[n];
153 final double h = (max - min) / n;
154 for (int i = 0; i < n; i++) {
155 s[i] = f.applyAsDouble(min + i * h);
156 }
157 return s;
158 }
159 }